iOS之运行时(Runtime)




  1. 动态编程语言和静态编程语言的区别
    • 动态编程语a言:在程序运行过程中可以改变数据类型的结构,对象的函数,变量可以被修改删除。例如OC
    • 静态编程语言:在程序编译阶段检查数据的类型,数据类型的结构不可以在运行时被改变。例如C
  2. Runtime---运行时系统是一个有公开接口的动态库,由一些数据结构和函数的集合组成,这些数据结构和函数的声明头文件,在/usr/include/objc,这些函数支持用纯C的函数来实现和Objective-C同样的功能
  3. Runtime---是开源的,目前苹果公司和GNU各自维护一个开源的runtime版本,apple open runtime;
  4. Runtime---在OC中的使用方式
    • 通过Objective-C源代码
    • 通过类NSObject的方法
    •      
           
      1. class 返回对象的类
        isKindeOfClass:和isMemberOfClass: 检查对象是否在指定的类继承体系中
        respondsToSelector: 检查对象能否响应指定的消息
        conformsToProtocol: 检查对象是否实现了指定协议类的方法
        methodForSelector: 返回指定方法实现的地址
    • 通过运行时系统的函数
      通过导入头文件"#import<objc/message.h>"调用相关函数

iOS中的消息机制

  1. Objective-C中消息机制的相关概念

    • message(消息) --包括了函数名+参数列表的一种抽象
    • method(方法)-- 是真正的存在的代码。如:- (int)meaning { return 42; }
    • selector(方法选择器)--通过SEL类型存在,描述一个特定的method 或者说 message。在实际编程中,可以通过selector进行检索方法等操作
    • SEL(方法选择器) -- 是一个char*指针,仅仅表示它所代表的方法名字,SEL只是一个指向方法的指针(准确的说,只是一个根据方法名hash化了的KEY值,能唯一代表一个方法),它的存在只是为了加快方法的查询速度


            
            
      //SELSEL selector = @selector(message); //@selector不是函数调用,只是给这个坑爹的编译器的一个提示
      NSLog (@"%s", (char *)selector); //print message
      //以下函数命名方式这被认为是一种编译错误
      -(void)setWidth:(int)width
      -(void)setWidth:(double)width
      /*IMP --函数指针
      我们可以通过SEL方便、快速、准确的获得它所对应的IMP(也就是函数指针),而在取得了函数指针之后,也就意味着我们取得了执行的时候的这段方法的代码的入口,这样我们就可以像普通的C语言函数调用一样使用这个函数指针。当然我们可以把函数指针作为参数传递到其他的方法,或者实例变量里面,从而获得极大的动态性*/

Runtime的作用

关联对象:主要为分类增加属性和实例变量。

能用扩展一般不用继承,因为随着继承深度的增加,代码可维护性变差

 
 
  1.  static char myKey;  //定义一个静态字符/*!
      *  给关联对象赋值
      *
      *  @param self 需要添加关联的分类
      *  @param key  const void *,key仅仅是一个地址,不是字符串内容。具体指向内容不用关心
      *  @param value 关联对象的值
      *  @param policy 关联策略,类似于对象的属性修饰符,OBJC_ASSOCIATION_RETAIN_NONATOMIC
      *
      */
      objc_setAssociatedObject(self, &myKey, model, OBJC_ASSOCIATION_RETAIN_NONATOMIC);  //给关联对象赋值/*!
      *  根据关联的key,获取关联的值
      *
      *  @param self  需要添加关联的分类
      *  @param myKey onst void *,key仅仅是一个地址,不是字符串内容。具体指向内容不用关心
      *
      *  @return 关联的对象的值
      */
      objc_getAssociatedObject(self, &myKey);


获取对象的私有变量,私有方法,动态添加属性、方法等。

  • 获取类名
 
 
  1. Class class = [objc class];
    class_getName(class);
    class_getSuperclass(class);
  • 获取成员变量(可以获取私有成员变量)

 
 
  1. CaculatorMaker *make = [[CaculatorMaker alloc] init];
    Class objcClass = [make class];unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList(objcClass, &outCount);
    for (int i = 0; i<outCount; i++) {
    Ivar ivar = ivars[i];const char *ivarString = ivar_getName(ivar);
    NSLog(@"the variable of make is %s",ivarString);
    }
    free(ivars);
  • 获取属性
 
 
  1. /*!
    *  获取对象的所有属性和属性值
    *
    *  @param object 对象
    *
    *  @return 属性和属性值数组
    */- (NSMutableArray *)getObjectPropertyAndValues:(id)object
    {    NSMutableArray *array = [NSMutableArray new];
       Class objcClass = [object class];    
       unsigned int outCount = 0 ;
       objc_property_t *properties = class_copyPropertyList(objcClass, &outCount);  
        for (int i = 0; i < outCount; i++) {
         objc_property_t property = properties[i];      
         const char *propertyName = property_getName(property);      
        NSString *propertyKey = [NSString stringWithUTF8String:propertyName];      
        NSString *propertyValue = [object valueForKey:propertyKey];
         RACTuple *tuple = RACTuplePack(propertyKey,propertyValue);
         [array addObject:tuple];
       }    return array;
     }
  • 动态添加方法
 
 
  1. CaculatorMaker *make = [[CaculatorMaker alloc] init];
    /*!
    *  runtime添加方法
    *
    *  @param class     被添加方法的类
    *  @param addMethod: 方法的名称
    *  @param imp:  实现这个方法的函数
    *  @param type: 定义函数返回值类型和参数类型的字符串
    [Type Encodings](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html)
    *  @return 添加成功或者失败
    */
    class_addMethod([make class], @selector(addMethod:), (IMP)addMethod, "i@:@");
    [make performSelector:@selector(addMethod:) withObject:@"new Method"];
    //添加的方法的具体实现int addMethod(id self, SEL _cmd, NSString *str)
    {NSLog(@"new method is %@",str);return 100;
    }


  • 动态添加属性和成员变量均未成功,属性添加完成之后的setter方法和getter方法不会实现。
  1. 消息转发(message forwarding)-当一个对象无法接收某一消息时,就会启动消息转发机制。
    通过这一机制,我们可以告诉对象如何处理未知的消息。默认情况下,对象接收到未知的消息,会导致程序崩溃。

    • 消息转发的步骤:1.动态方法解析 2.备用接收者 3. 完整转发
    • 动态方法解析:当对象接收到未实现的方法时,为自动调用resolveInstanceMethod:和resolveClassMethod:
 
 
  1. //当对象接收到未知方法时,动态添加以下方法。作为默认执行,防止程序崩溃
    void functionForMethod1(id self, SEL _cmd)
    {  NSLog(@"当未实现某个方法时默认执行此函数");
    }
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
     class_addMethod(self.class, @selector(method1), (IMP)functionForMethod1, "@:");  return [super resolveInstanceMethod:sel];
    }
     
    + (BOOL)resolveClassMethod:(SEL)sel
    {
     class_addMethod(self.class, @selector(method1), (IMP)functionForMethod1, "@:");  return [super resolveClassMethod:sel];
    }


    • 备用接收者:如果没有用动态方法解析处理消息,则Runtime会继续调以下方法:

  •     
        
    1. //如果对象实现了这个方法,并返回一个非nil的值,则这个对象会作为消息的接收者。且消息会被分发到这个对象- (id)forwardingTargetForSelector:(SEL)aSelector {id  standByObj;
      //....standByObj 备用接收对象的初始化等操作return standByObj;
      return [super forwardingTargetForSelector:aSelector];
      }
  • 完整转发:如果在上一步还不能处理未知消息,则唯一能做的就是启用完整的消息转发机制了

  
  
  1. /*!
    *  消息转发机制使用从这个方法中获取的信息来创建NSInvocation对象。因此我们必须重写这个方法,为给定的selector提供一个合适的方法签名
    *
    *  @param aSelector 需要转发的方法
    *
    *  @return 新的方法签名
    */
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {  NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];    
    if (!signature) {  
    if ([SUTRuntimeMethodHelper instancesRespondToSelector:aSelector]) {
     
           signature = [SUTRuntimeMethodHelper instanceMethodSignatureForSelector:aSelector];
       }
     }  return signature;
    }
    /*!
    *  将消息转发给其它对象
    *
    *  @param anInvocation 需要转发的消息的selector,目标(target)和参数
    */
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {  
     if ([SUTRuntimeMethodHelper instancesRespondToSelector:anInvocation.selector]) {
     
       [anInvocation invokeWithTarget:_helper];
     }
    }

  1. 方法交换(Method Swizzling)

    • 给view controller的viewWillAppear:中添加跟踪代码,将viewWillAppear:与自定义的dg_viewWillAppear:交换,代码如下:
  
  
  1. #import "UIViewController+Tracking.h"
    #import <objc/runtime.h>
    @implementation UIViewController (Tracking)
    /*!
    *  在load中实现方法交换,
    */
    + (void)load
    {  //static dispatch_once_t onceToken;  dispatch_once(&onceToken,^{
         Class class = [self class];
         SEL originalSelector = @selector(viewWillAppear:);
         SEL swizzledSelector = @selector(dg_viewWillAppear:);
         Method originalMethod = class_getInstanceMethod(class, originalSelector);
         Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);      
        //本类是否已添加swizzledMethod,未添加则进行添加
        BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));    
          if (didAddMethod) {
             class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
             } else{
               method_exchangeImplementations(originalMethod, swizzledMethod);
             }
             });
           }
    - (void)dg_viewWillAppear:(BOOL)animated
    {
     [self dg_viewWillAppear:animated];  NSLog(@"viewWilleAppear");
    }
    @end


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS Runtime是一种运行时环境,它是iOS操作系统中的重要组成部分。iOS Runtime开发者提供了一套动态询问、修改和扩展应用程序行为的机制。 首先,iOS Runtime实现了Objective-C语言的动态特性。Objective-C是一种面向对象的编程语言,它具有动态特性,即在运行时能够动态地修改对象的行为。iOS Runtime允许开发者通过运行时系统对类、对象、方法以及属性进行动态操作。例如,开发者可以在运行时为某个类添加新的方法,也可以通过运行时修改类的实例变量。 其次,iOS Runtime还提供了消息发送机制。在Objective-C中,对象之间的通信是通过消息发送来完成的。iOS Runtime负责将消息转发给正确的接收者,并执行相应的方法。这个过程是动态的,开发者可以在运行时动态改变消息的接收者或方法的实现。这为Objective-C语言带来了很高的灵活性。 此外,iOS Runtime还支持方法的交换与替换。开发者可以通过运行时机制,在运行时将一个方法的实现替换为另一个方法的实现,或者交换两个方法的实现。这对于调试、性能监控和代码扩展都是非常有用的。 总结来说,iOS RuntimeiOS操作系统中实现Objective-C语言特性的核心组件。它提供了动态特性的支持,使开发者能够在运行时动态地修改类、对象和方法的行为,实现更加灵活和可扩展的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值