美文网首页
runtime基础

runtime基础

作者: UILabelkell | 来源:发表于2017-04-18 14:14 被阅读20次

    目前我所了解的Runtime内容大约有:动态获取类名、动态获取类的成员变量、动态获取类的属性列表、动态获取类的方法列表、动态获取类所遵循的协议列表、动态添加新的方法、类的实例方法实现的交换、动态属性关联、消息发送与消息转发机制
    1、实现方法交换
    <pre>
    -(void)initWithVie
    {
    UIButton *btu = [UIButton buttonWithType:UIButtonTypeCustom];
    btu.frame = CGRectMake(100, 100, 80, 40);
    btu.backgroundColor = [UIColor orangeColor];
    [btu addTarget:self action:@selector(clickent:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btu];
    }

    -(void)clickent:(UIButton *)btn
    {
    Method m1 = class_getInstanceMethod([self class], @selector(stringStr));
    Method m2 = class_getInstanceMethod([self class], @selector(withview));
    method_exchangeImplementations(m1, m2);

    [self stringStr];
    [self withview];
    

    }

    -(void)stringStr
    {
    NSLog(@"%s ---1",FUNCTION);
    }

    -(void)withview
    {
    NSLog(@"%s---2",FUNCTION);
    }
    </pre>
    原理:OC的方法调用会在底层转换为向该对象发送消息。这由C语言的函数完成。是通过查找接收消息对象的方法列表,从方法列表中查找对应的SEL,这个SEL对应着一个IMP(一个IMP可以对应多个SEL),通过这个IMP找到对应的方法调用。

    在每个类中都有一个Dispatch Table,这个Dispatch
    Table本质是将类中的SEL和IMP(可以理解为函数指针)进行对应。而我们的Method
    Swizzling就是对这个table进行了操作,让SEL对应另一个IMP。
    如图
    交换前:


    003YMHs7gy72CEFH1e525&690.jpeg

    交换后

    003YMHs7gy72CEKEp7r51&690.jpeg

    2.获取类名 方法
    <pre>
    /**
    获取类名

    @param class 相应类
    @return NSString:类名
    */

    • (NSString *)fetchClassName:(Class)class {
      const char *className = class_getName(class);
      return [NSString stringWithUTF8String:className];
      }
      用法:
      const char *className = class_getName([TestClass class]);
      NSLog(@"%@",[NSString stringWithUTF8String:className]);
      </pre>

    3.获取成员变量
    <pre>/**
    获取成员变量

    @param class Class
    @return NSArray
    */

    • (NSArray *)fetchIvarList:(Class)class {
      unsigned int count = 0;
      Ivar *ivarList = class_copyIvarList(class, &count);

      NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
      for (unsigned int i = 0; i < count; i++ ) {
      NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:2];
      const char *ivarName = ivar_getName(ivarList[i]);
      const char *ivarType = ivar_getTypeEncoding(ivarList[i]);
      dic[@"type"] = [NSString stringWithUTF8String: ivarType];
      dic[@"ivarName"] = [NSString stringWithUTF8String: ivarName];

        [mutableList addObject:dic];
      

      }
      free(ivarList);
      return [NSArray arrayWithArray:mutableList];
      }
      常量:共享一块内存空间,就算项目中N处用到,也不会分配N块内存空间,可以根据const修饰的位置设定能否修改,在编译阶段会执行类型检查
      调用方法
      [Ruck fetchIvaList:[TestClass class]]

      unsigned int count = 0;
      Ivar *ivarList = class_copyIvarList([TestClass class], &count);
      NSMutableArray *mutable = [NSMutableArray arrayWithCapacity:count];
      for (unsigned int i = 0; i < count; i++) {
      NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:2];
      const char *ivarName = ivar_getName(ivarList[i]);
      const char *ivarType = ivar_getTypeEncoding(ivarList[i]);
      dic[@"type"] = [NSString stringWithUTF8String: ivarType];
      dic[@"ivarName"] = [NSString stringWithUTF8String: ivarName];
      [mutable addObject:dic];
      }
      free(ivarList);
      NSLog(@"is a mutable--%@",mutable);

    </pre>

    3.获取类的属性列表, 包括私有和公有属性,以及定义在延展中的属性
    <pre>/**
    获取类的属性列表, 包括私有和公有属性,以及定义在延展中的属性

    @param class Class
    @return 属性列表数组
    */

    • (NSArray *)fetchPropertyList:(Class)class {
      unsigned int count = 0;
      objc_property_t *propertyList = class_copyPropertyList(class, &count);

      NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
      for (unsigned int i = 0; i < count; i++ ) {
      const char *propertyName = property_getName(propertyList[i]);
      [mutableList addObject:[NSString stringWithUTF8String: propertyName]];
      }
      free(propertyList);
      return [NSArray arrayWithArray:mutableList];
      }
      </pre>

    4.获取类的实例方法列表:getter, setter, 对象方法等。但不能获取类方法
    <pre>/**
    获取类的实例方法列表:getter, setter, 对象方法等。但不能获取类方法

    @param class <#class description#>
    @return <#return value description#>
    */

    • (NSArray *)fetchMethodList:(Class)class {
      unsigned int count = 0;
      Method *methodList = class_copyMethodList(class, &count);

      NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
      for (unsigned int i = 0; i < count; i++ ) {
      Method method = methodList[i];
      SEL methodName = method_getName(method);
      [mutableList addObject:NSStringFromSelector(methodName)];
      }
      free(methodList);
      return [NSArray arrayWithArray:mutableList];
      }
      </pre>

    1. 获取协议列表
      <pre>/**
      获取协议列表

    @param class <#class description#>
    @return <#return value description#>
    */

    • (NSArray *)fetchProtocolList:(Class)class {
      unsigned int count = 0;
      __unsafe_unretained Protocol **protocolList = class_copyProtocolList(class, &count);

      NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
      for (unsigned int i = 0; i < count; i++ ) {
      Protocol *protocol = protocolList[i];
      const char *protocolName = protocol_getName(protocol);
      [mutableList addObject:[NSString stringWithUTF8String: protocolName]];
      }

      return [NSArray arrayWithArray:mutableList];
      return nil;
      }
      </pre>

    1. 往类上添加新的方法与其实现
      <pre>
      /**
      往类上添加新的方法与其实现

    @param class 相应的类
    @param methodSel 方法的名
    @param methodSelImpl 对应方法实现的方法名
    */

    • (void)addMethod:(Class)class method:(SEL)methodSel method:(SEL)methodSelImpl {
      Method method = class_getInstanceMethod(class, methodSelImpl);
      IMP methodIMP = method_getImplementation(method);
      const char *types = method_getTypeEncoding(method);
      class_addMethod(class, methodSel, methodIMP, types);
      }
    • (void)method1 {
      NSLog(@"我是Method1的实现");
      }

    //运行时方法拦截

    • (void)dynamicAddMethod: (NSString *) value {
      NSLog(@"OC替换的方法:%@", value);
      }

    /**
    没有找到SEL的IML实现时会执行下方的方法

    @param sel 当前对象调用并且找不到IML的SEL
    @return 找到其他的执行方法,并返回yes
    */

    • (BOOL)resolveInstanceMethod:(SEL)sel {
      return NO; //当返回NO时,会接着执行forwordingTargetForSelector:方法,
      [RuntimeKit addMethod:[self class] method:sel method:@selector(dynamicAddMethod:)];
      return YES;
      }

    /**
    将当前对象不存在的SEL传给其他存在该SEL的对象

    @param aSelector 当前类中不存在的SEL
    @return 存在该SEL的对象
    */

    • (id)forwardingTargetForSelector:(SEL)aSelector {
      return self;
      return [SecondClass new]; //让SecondClass中相应的SEL去执行该方法
      }

    • (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
      //查找父类的方法签名
      NSMethodSignature *signature = [super methodSignatureForSelector:selector];
      if(signature == nil) {
      signature = [NSMethodSignature signatureWithObjCTypes:"@@:"];

      }
      return signature;
      }

    • (void)forwardInvocation:(NSInvocation *)invocation {
      SecondClass * forwardClass = [SecondClass new];
      SEL sel = invocation.selector;
      if ([forwardClass respondsToSelector:sel]) {
      [invocation invokeWithTarget:forwardClass];
      } else {
      [self doesNotRecognizeSelector:sel];
      }
      }
      </pre>

    相关文章

      网友评论

          本文标题:runtime基础

          本文链接:https://www.haomeiwen.com/subject/ccwfzttx.html