我们都知道OC是动态语言,表现为对象方法的调用实际上是对对象发送消息,编译时不确定这个对象执行什么方法,而在运行时由消息(方法选择器selector决定对象执行什么方法),这种消息发送的方式叫做动态绑定
oc是一门动态语言,它允许操作在运行的时候才执行
oc的这种特性是基于runtime实现的,runtime底层是由c语言编写,oc编写的代码在执行的时候最终都会转化成runtime api进行运行。
oc的消息转发机制
在调用对象的方法的时候,编译器会转化为objc_msgSend(obj, @selector (makeText));通过对象的isa指针去对象的class中查找对应的方法去执行,分为以下几步
- 获取传入对象所属的类。
- 使用传入的selector在缓存
cache
列表中查询。 - 如果找到了方法,则通过
Method
中的IMP
(方法实现的地址)去调用方法。 - 如果缓存中不存在,则开始在
methodLists
列表中查找。 - 如果
methodLists
列表找不到,利用super_class
指针去父类查找, - 递归地查找父类,一直查找到
NSObject
,如果还是找不到,则触发消息转发机制。
如果当前类和父类中都没有找到对应的方法,执行一下几步操作
1⃣️动态方法解析
动态方法解析:向当前类发送 resolveInstanceMethod: 信号,检查是否动态向该类添加了方法。
2⃣️尝试快速消息转发
检查该类是否实现了 forwardingTargetForSelector: 方法,若实现了则调用这个方法。若该方法返回值对象非nil或非self,则向该返回对象重新发送消息
3⃣️尝试标准消息转发
runtime发送methodSignatureForSelector:消息获取Selector对应的方法签名。返回值非空则通过forwardInvocation:转发消息,返回值为空则向当前对象发送doesNotRecognizeSelector:消息,程序崩溃退出
4⃣️抛出异常
@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法
@dynamic告诉编译器:属性的setter与getter方法由用户自己实现,不自动生成(当然对于readonly的属性只需提供getter即可)
假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var = someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = instance.var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定