方法的調(diào)用本質(zhì):消息發(fā)送/轉(zhuǎn)發(fā)機(jī)制 案例

1.0、方法的實(shí)現(xiàn)
 * 獲取實(shí)例方法:class_getInstanceMethod(Class cls, SEL name)
 * 設(shè)置類方法:  class_getClassMethod(Class cls, SEL name)
 * 獲取方法指針:method_getImplementation(Method m) 
 * 設(shè)置方法指針:method_setImplementation(Method m, IMP imp) (方法可以重新指向)
 * 設(shè)置對(duì)象的類:object_setClass(id obj, Class cls) 
1、消息發(fā)送(方法調(diào)用的本質(zhì))
 * 注冊(cè)方法:sel_registerName(const char *str),sel_registerName("new")
 * 消息發(fā)送:objc_msgSend(id self, SEL op, ...)
 * 創(chuàng)建一類:objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes) 
    objc_msgSend(消息接受者,消息名稱)
    objc_msgSend(person, sel_registerName("walk"));
    objc_msgSend(objc_getClass("TZPerson"), sel_registerName("addRun"));
    Class TZCat = objc_allocateClassPair([NSObject class], "TZCat", 0);
2、消息轉(zhuǎn)發(fā):動(dòng)態(tài)方法解析
  • 對(duì)象在收到無法解讀的消息后:調(diào)用+ (BOOL)resolveInstanceMethod:(SEL)sel來動(dòng)態(tài)為其 添加實(shí)例方法,來處理該選擇。
  • 如果尚未實(shí)現(xiàn)的方法是類方法:調(diào)用+ (BOOL)resolveClassMethod:(SEL)sel來動(dòng)態(tài)為其 添加類方法
//#pragma mark --- 實(shí)例方法 的轉(zhuǎn)換:+ (BOOL)resolveInstanceMethod:(SEL)sel
//#pragma mark --- 實(shí)例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"---resolveInstanceMethod:%s", __func__);
    // 元類 
    // 實(shí)例對(duì)象、類對(duì)象、元類對(duì)象
    //例6.2.1:無方法,構(gòu)建一個(gè)方法,并去調(diào)用實(shí)現(xiàn)
    if (sel == @selector(walk)) {
        //創(chuàng)建實(shí)例方法(向?qū)嵗l(fā)送消息,在類上添加方法)
        Method runMethod = class_getInstanceMethod(self, @selector(run));
        //方法指針
        IMP runIMP = method_getImplementation(runMethod);
        //描述方法參數(shù)的類型
        const char* types = method_getTypeEncoding(runMethod);
        NSLog(@"---(實(shí)例方法)types:%s", types); //v16@0:8  參數(shù)字節(jié)數(shù)16 @從第幾個(gè)字節(jié)開始 :表示第8個(gè)       
        return class_addMethod(self, sel, runIMP, types);
    }
    //有方法,去調(diào)用實(shí)現(xiàn),
    return [super resolveInstanceMethod:sel];
}


//#pragma mark --- 類方法 的轉(zhuǎn)換:+ (BOOL)resolveClassMethod:(SEL)sel
//#pragma mark --- 類方法
+ (BOOL)resolveClassMethod:(SEL)sel {
    NSLog(@"---resolveClassMethod:%s", __func__);
    //例6.2.2:(類方法)無方法,構(gòu)建一個(gè)方法,并去調(diào)用實(shí)現(xiàn)
    if (sel == @selector(walk)) {
        //創(chuàng)建類方法(向類發(fā)送消息,在元類上添加方法)
        Method runMethod = class_getInstanceMethod(object_getClass(self), @selector(run));
        //方法指針
        IMP runIMP = method_getImplementation(runMethod);
        //描述方法參數(shù)的類型
        const char* types = method_getTypeEncoding(runMethod);
        NSLog(@"---(類方法)types:%s", types); //v16@0:8  參數(shù)字節(jié)數(shù)16 @從第幾個(gè)字節(jié)開始 :表示第8個(gè)       
        return class_addMethod(object_getClass(self), sel, runIMP, types);
    }
    //有方法,去調(diào)用實(shí)現(xiàn),
    return [super resolveClassMethod:sel];
}
3、消息轉(zhuǎn)發(fā):快速轉(zhuǎn)發(fā)、完成轉(zhuǎn)發(fā)

掛載到其他類的方法上。
是否有消息轉(zhuǎn)發(fā):有就去調(diào)用、沒有就崩潰。
既然已經(jīng)問過了,沒有新增方法,那就問問有沒有別人能夠幫忙處理一下:

「v@: 的含義」
v表示方法的返回類型是 void(即沒有返回值)。
@表示方法的第一個(gè)參數(shù)是 id 類型(即 Objective-C 對(duì)象)。
: 表示方法的第二個(gè)參數(shù)是 SEL 類型(即方法選擇器)。

\\實(shí)例方法 處理
- (id) forwardingTargetForSelector:(SEL)aSelector
- (NSMethodSignature* )methodSignatureForSelector:(SEL)aSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation

\\類方法 處理
+ (id) forwardingTargetForSelector:(SEL)aSelector
+ (NSMethodSignature* )methodSignatureForSelector:(SEL)aSelector
+ (void)forwardInvocation:(NSInvocation *)anInvocation

源碼如下:

# ------------------------- (實(shí)例:消息轉(zhuǎn)發(fā)) ---------------------------
# 7.1: 實(shí)例方法(方法掛載,掛載到其他類上)
# 方式一
- (id) forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(walk7)) {
        return [TZDog new];
    }    
    return [super forwardingTargetForSelector:aSelector];
}

# 方式二
# 方法名注冊(cè) 
- (NSMethodSignature* )methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(walk7)) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}
# 消息轉(zhuǎn)發(fā):實(shí)例方法
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    //NSLog(@"%s", __func__);
    //[anInvocation invokeWithTarget:[TZDog new]];   // 轉(zhuǎn)發(fā)給 其他
    // 轉(zhuǎn)發(fā)給 自己
    anInvocation.selector = @selector(run);
    anInvocation.target = self;
    [anInvocation invoke];
}

## ------------------------- (類:消息轉(zhuǎn)發(fā)) ---------------------------
##  7.2:類方法 消息轉(zhuǎn)發(fā)
##  方式一
+ (id) forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(walk7)) {
        //return [TZDog new]; //可以轉(zhuǎn)發(fā)到:類的實(shí)例方法
         return [TZDog class];//可以轉(zhuǎn)發(fā)到:類方法 
     }    
    return [super forwardingTargetForSelector:aSelector];
}

##  方式二
# 方法名注冊(cè) 
+ (NSMethodSignature* )methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(walk7)) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
} 
# 消息轉(zhuǎn)發(fā):類方法
+ (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@" 轉(zhuǎn)發(fā)給 其他= %s", __func__);   
    //[anInvocation invokeWithTarget:[TZDog new]];   //可以轉(zhuǎn)發(fā)到:類的實(shí)例方法
    //[anInvocation invokeWithTarget:[TZDog class]]; //可以轉(zhuǎn)發(fā)到:類方法

    // 轉(zhuǎn)發(fā)給 自己
    anInvocation.selector = @selector(run);
    anInvocation.target = self;
    [anInvocation invoke];
}
# ------------------------- 結(jié)束(消息轉(zhuǎn)發(fā)) ---------------------------
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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