Runtime

meta class总结:

  • 类的实例对象的 isa 指向它的类;类的 isa 指向该类的 metaclass
  • 类的 super_class 指向其父类,如果该类为根类则值为 nil
  • metaclass 的 isa 指向根 metaclass,如果该 metaclass 是根 metaclass 则指向自身
  • metaclass 的 super_class 指向父 metaclass,如果该 metaclass 是根 metaclass 则指向该 metaclass 对应的类;
    如图所示


    Runtime_第1张图片
    super class 和meta class
示例:(来自参考1第二题)

下面的代码是报错、警告、正常输出?

Father *father = [Father new];
BOOL b1 = [father responseToSelector:@selector(responseToSelector:)];
BOOL b2 = [Father responseToSelector:@selector(responseToSelector:)];
NSLog(@"%d, %d", b1, b2);

答案是正常输出,均为YES。原因:

  • 不论是实例对象还是 Class,都是 id 类型的对象(Class 也是对象)
  • 实例对象的 isa 指向它的 Class(储存所有减号方法),Class 对象的 isa 指向元类(储存所有加号方法)
  • 向一个对象(id 类型的对象)发送消息时,都是从这个对象的 isa 指针指向的 Class 中寻找方法
    回到题目,当向 Father 类发送一个实例方法(- responseToSelector)消息时
  1. 会从它的 isa ,也就是 Father 元类对象中寻找,由于元类中的方法都是类方法,自然找不到
  2. 于是沿着继承链去父类 NSObject 的元类中寻找,依然找不到
  3. 由于 objc 这块的设计,Objc 元类的父类是 NSObject 类(也就是我们熟悉的 NSObject 类),其中有所有的实例方法,因此找到了- responseToSelector

objc_msgSend工作原理

在Objective-C中,消息直到运行时才会绑定到方法的实现上。编译器会把代码中[target doSth]转换成 objc_msgSend消息函数,这个函数完成了动态绑定的所有事情。它的运行流程如下:

  1. 检查selector是否需要忽略。(ps: Mac开发中开启GC就会忽略retain,release方法。)
  2. 检查target是否为nil。如果为nil,直接cleanup,然后return。(这就是我们可以向nil发送消息的原因。)
  3. 然后在target的Class中根据Selector去找IMP
寻找IMP的过程:
  1. 先从当前class的cache方法列表(cache methodLists)里去找
  2. 找到了,跳到对应函数实现
  3. 没找到,就从class的方法列表(methodLists)里找
  4. 还找不到,就到super class的方法列表里找,直到找到基类(NSObject)为止
  5. 最后再找不到,就会进入动态方法解析和消息转发的机制。

Runtime常见应用

具体见下面文章
Runtime常见作用举例

未完待续

参考

  1. iOS 程序员 6 级考试(答案和解释)

你可能感兴趣的:(Runtime)