Runtime1 -OC的消息機制

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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容