关于Runtime,我有话要说


关于Runtime,我有话要说_第1张图片
图是网上找的.jpg

简介

    Objective-C(下面简称OC) 是基于面向对象思想而对C 语言进行扩展的一种动态编程语言,而这个扩展的核心是Runtime。Runtime是一个用C语言和汇编语言写的动态库,它是整个OC运行框架的一块基石。

与Runtime交互

    与Runtime交互有三种方式,分别是:
  1.通过Objective-C 源代码
       
大部分情况下我们都是使用OC在XCode开发工具上进行项目开发,而不需要涉及到Runtime的使用。比如,当我们调用对象方法-(void)doSomething:(NSString *)str时,只需要在键盘上敲出"[self doSomething:@"xxx"];"即可,编译过程中系统会自动帮我们转换为"objc_msgsend(person,@selector(doSomething),@"xxx");"。
    2.通过 Foundation 框架的NSObject类定义的方法
        Cocoa中大部分类都是NSObject的子类,都继承了NSObject的行为。NSObject类中一些方法可以从Runtime系统中获取信息,如:
       -class   方法返回对象的类;
      -isKindOfClass:和-isMemberOfClass:方法检查对象是否存在于指定的类的继承体系中(是否是其子类或者父类或者当前类的成员变量);
      -respondsToSelector:检查对象能否响应指定的消息;
    3.通过对 runtime 函数的直接调用
     
Runtime 系统是一个由一系列函数和数据结构组成,具有公共接口的动态共享库。使用前需要先导入。类的操作方法大部分是以class为前缀的,而对象的操作方法大部分是以objc或object为前缀。

Runtime基础数据结构

1.Class
       
Class实际上是一个指向objc_class结构体的指针,对objc_class结构体的定义如下

关于Runtime,我有话要说_第2张图片
object_class结构体.jpg

定义中有几个重要的字段:
     1)isa:Objc中所有的类自身也是一个对象,这个对象的class也有一个isa指针,指向metaClass元类。
      2) super_class: 指向该类的父类,如果该类是顶部根类,则super_class 为NULL。
      3) cache: 用于缓存最近使用的方法,该方法可以有效提高查询指定方法的效率。
2.Meta Class(元类)
     
meta class 是一个类对象的类,当我们向一个对象发送消息时,runtime会在这个对象所属的类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta class的方法列表中查找。而meta class作为一个类,它的isa指向基类的meta class,基类的meta class的isa指针又指向它自己。

关于Runtime,我有话要说_第3张图片
网上找的图.jpg

3.Method

class_addMethod.jpg

Method是一种代表类中的某个方法的类型。图中的函数为为类添加方法,从参数可知Method结构体有SEL字段、IMP字段、char字段。SEL类型仅代表方法名,即使相同方法名的方法在不同类中定义,但方法选择器还是相同的。types表示方法的参数类型和返回值类型。IMP是一个函数指针,指向了函数体,即函数的实现。

消息发送

      当消息发送给一个对象时,objc_msgSend通过对象的isa指针获取到类的结构体,然后在方法列表中查找方法的selector。如果没有找到selector,则通过super_class找到父类,在父类的方法列表中查找selector,以此类推。若最后没有找到selector,则会进行消息转发。

消息转发

     当以"[object message]"方式调用方法时候,若找不到selector则编译器会报错。若以“perform...”形式来调用,则需要等到运行时才能确定object是否能接收message消息。如果不能则程序崩溃。消息转发机制分为三个步骤:
    1).动态方法解析
    2).备用接收者
    3). 完整转发
  1.动态方法解析
         
对象接收到未知消息时,调用resolveInstanceMethod:。在这个方法中,我们有机会为该未知消息新增一个处理方法。

关于Runtime,我有话要说_第4张图片
重写方法.jpg

  2.备用接收者
    若没有新增处理方法,则会调用forwardingTargetForSelector方法。如果一个对象实现了这个方法,并返回一个非nil的结果,则这个对象会作为消息的新接收者,而且消息会被分发到这个对象。

关于Runtime,我有话要说_第5张图片
备用接收者.jpg

 3.完整消息转发
    若还是不能处理未知消息,则只能启用完整的消息转发机制。调用forwardInvocation:方法。对象会创建一个表示消息的NSInvocation 对象。把与消息有关的信息都封装到NSInvocation里面,包括selector、target和参数。在该方法中选择将消息转发给其它对象。还有一点,我们需要重写methodSignatureForSelector:方法,消息转发机制从这个方法获取的信息来创建NSInvocation对象,因为我们需要重写这个方法并为给定的selector提供一个合适的方法签名。PS:下图Viewcontroller只是一个普通的类。

关于Runtime,我有话要说_第6张图片
完整消息转发.jpg


整个过程如下图所示:

关于Runtime,我有话要说_第7张图片
网上找的图.jpg



Method Swizzling(方法替换)

在Objc中,运行时会自动调用每个类的两个方法。+load 会在类初始加载时调用,+initialize会在第一次调用类的类方法或实例方法之前被调用。由于方法替换会影响到类的全局状态,因此要尽量避免在并发处理中出现竞争情况。

关于Runtime,我有话要说_第8张图片
method swizzling.jpg

要注意的是swizzling应该总在+load且dispatch_once中执行。+load能保证在类的初始化过程中被加载,并保证这种改变应用级别的行为的一致性。相比之下,+initialize在其执行时不提供这种保证。

总结

   深入理解Runtime 更有利于我们利用消息机制写出更强大的代码,菜鸟一枚,请喷轻一点~

参考博客:http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/
                  http://southpeak.github.io/categories/objectivec/

你可能感兴趣的:(关于Runtime,我有话要说)