objc_msgSend的執(zhí)行流程可以分為三大階段:消息發(fā)送苔巨、動態(tài)方法解析蜒灰、消息轉(zhuǎn)發(fā)
1.消息發(fā)送
大致流程:先在本類的方法緩存列表中查找枣耀、再在本類的方法列表中查找(如果是類方法在元類的方法列表中查找)课锌、如果還沒找到繼續(xù)在父類中查找乔宿。詳細(xì)流程看下圖:
注:方法只會緩存在receiverClass的cache中,而不會在父類中緩存像樊。
2.動態(tài)方法解析
如果第一步?jīng)]有成功找到方法就會執(zhí)行動態(tài)方法解析尤莺,動態(tài)方法解析實際上就是動態(tài)添加方法,當(dāng)然這里的方法也分為對象方法和類方法生棍,
看代碼:
- (void)eat{
NSLog(@"吃...");
}
// 動態(tài)添加實例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(eat)) {
Method method = class_getInstanceMethod(self, sel);
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super resolveInstanceMethod:sel];
}
+ (void)sleep{
NSLog(@"睡...");
}
// 動態(tài)添加類方法
+ (BOOL)resolveClassMethod:(SEL)sel{
if (sel == @selector(sleep)) {
Method method = class_getClassMethod(self, sel);
class_addMethod(object_getClass(self), sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super resolveClassMethod:sel];
}
實例對象和類對象都能調(diào)用performSelector方法
最終動態(tài)添加的方法會被添加到方法列表中颤霎。
個人認(rèn)為動態(tài)方法解析在實際開發(fā)中應(yīng)用并不多。
3.消息轉(zhuǎn)發(fā)
看圖:
消息轉(zhuǎn)發(fā)分為實例對象和類對象(完整消息轉(zhuǎn)發(fā)和快速轉(zhuǎn)發(fā))涂滴。
看代碼:
/*對象方法的消息轉(zhuǎn)發(fā)**/
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(eat)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
[anInvocation invokeWithTarget:[Son new]];
}
方法簽名的作用:獲取函數(shù)的參數(shù)和返回值友酱。
/*類方法的消息轉(zhuǎn)發(fā)**/
+ (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(sleep)) {
return [Son class];
}
return [super forwardingTargetForSelector:aSelector];
}
如果這個類沒有實現(xiàn)這個方法,就把這個消息轉(zhuǎn)發(fā)給實現(xiàn)了這個方法(能響應(yīng)這個消息)的類柔纵。
之前兩篇文章里(
1.iOS開發(fā)中的消息轉(zhuǎn)發(fā)應(yīng)用于解決NSTimer
2.iOS開發(fā)中的內(nèi)存管理之解決NSTimer造成的循環(huán)引用
)提過利用消息轉(zhuǎn)發(fā)解決NSTimer循環(huán)引用的問題缔杉。
兩種不同的消息轉(zhuǎn)發(fā)方式有什么不同呢?
1.快速消息轉(zhuǎn)發(fā)只需實現(xiàn)一個方法搁料,而完整消息轉(zhuǎn)發(fā)需要實現(xiàn)兩個方法或详。
2.快速消息轉(zhuǎn)發(fā)只能轉(zhuǎn)發(fā)給一個接收者系羞,而完整消息轉(zhuǎn)發(fā)可以轉(zhuǎn)發(fā)給多個接收者。
轉(zhuǎn)發(fā)給多個接收者代碼
// 完整消息轉(zhuǎn)發(fā)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(test:)) {
// return [[[Student alloc]init] methodSignatureForSelector:aSelector];
return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
// anInvocation.target = [[Student alloc]init];
// [anInvocation invoke];
// 轉(zhuǎn)發(fā)給Student和Teacher兩個接收者
[anInvocation invokeWithTarget:[[Student alloc] init]];
[anInvocation invokeWithTarget:[Teacher new]];
}