OC中的方法調(diào)用底層轉(zhuǎn)成了objc_msgSend函數(shù)的調(diào)用,給receiver方法調(diào)用者發(fā)送一條@selector消息。
objc_msgSend底層有3大階段:
1:消息發(fā)送
首先根據(jù)receiver對象的isa找到類對象,在類對象的方法緩存cache中查找找到就調(diào)用,沒找到在類對象的class_rw_t的方法數(shù)組method_list中遍歷查找,找到就調(diào)用,并將方法緩存到類對象的cache中。沒找到根據(jù)super_class指針找到父類的類對象,在父類的方法緩存中查找,找到就調(diào)用,并存入receiver類對象的方法緩存中,沒找到在父類的方法列表中查找,找到就調(diào)用,并存入receiver類對象的方法緩存中,沒找到繼續(xù)根據(jù)super_class指針找到父類,在父類中查找。如果一直找到NSObject基類都沒有找到要調(diào)用的方法,進入動態(tài)方法解析。
2:動態(tài)方法解析 resolveInstanceMethod
調(diào)用resolveInstanceMethod/resolveClassMethod動態(tài)添加方法的實現(xiàn),成功添加方法實現(xiàn)后,該方法會存入class_rw_t的方法列表中。重新進入消息發(fā)送。如果消息發(fā)送階段仍然沒有找到要調(diào)用的方法,已經(jīng)進行過一次動態(tài)方法解析,直接進入消息轉(zhuǎn)發(fā)。
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(test)) {
Method method = class_getInstanceMethod(self, @selector(testMethod));
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
NSLog(@"%s", __func__);
return [super resolveInstanceMethod:sel];
}
- (void)testMethod {
NSLog(@"%s", __func__);
}
3:消息轉(zhuǎn)發(fā)forwardingTargetForSelector
調(diào)用forwardingTargetForSelector方法,如果轉(zhuǎn)給其他對象處理,會向返回對象發(fā)送消息。如果返回nil,沒有轉(zhuǎn)給其他對象處理,進入方法簽名methodSignatureForSelector。如果返回的方法簽名正確,進入forwardInvocaiton。
//類方法的消息轉(zhuǎn)發(fā)
+ (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(classMethod:)) {
NSLog(@"forwardingTargetForSelector");
//return [Doctor class]; //相當于objc_msgSend(Doctor, @selector(classMethod:));
//return [[Doctor alloc] init]; //相當于objc_msgSend([[Doctor alloc] init], @selector(classMethod:));
return nil;
}
return [super forwardingTargetForSelector:aSelector];
}
+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(classMethod:)) {
NSLog(@"methodSignatureForSelector");
return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
}
return [super methodSignatureForSelector:aSelector];
}
+ (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@"forwardInvocation");
int age;
[anInvocation getArgument:&age atIndex:2];
int ret;
[anInvocation getReturnValue:&ret];
NSLog(@"age = %d, ret = %d", age, ret);
}
//實例1
//攔截消息,避免報unrecognized selector send to instance錯誤(只有方法聲明,沒有方法實現(xiàn))
#pragma mark 方法簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if ([self respondsToSelector:aSelector]) {
return [super methodSignatureForSelector:aSelector];
}
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@"找不到%@方法", NSStringFromSelector(anInvocation.selector));
}
//實例2
[super class]的底層實現(xiàn)
1:消息接收者仍然是子類對象
2:從父類開始查找方法的實現(xiàn)
- (Class)class {
return object_getClass(self);
}
//獲取父類對象
- (Class)superclass {
return [self class]->superclass;
}
//Student繼承Person
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"[self class] = %@", [self class]); //Student
NSLog(@"[self superclass] = %@", [self superclass]); //Person
NSLog(@"-----------------");
NSLog(@"[super class] = %@", [super class]); //Student
NSLog(@"[super superclass] = %@", [super superclass]); //Person
}
return self;
}