OC 黑魔法之 Method Swizzling

基礎(chǔ)實(shí)現(xiàn)

Method swizzling(有些人也叫它方法交換)對(duì)絕大多數(shù)OC開發(fā)者來說都是很熟悉但并沒有太多應(yīng)用場(chǎng)景的一個(gè)東西。但是了解它對(duì)于了解OC底層runtime有很好的幫助。而且可以繞過一個(gè)限制,實(shí)現(xiàn)某些特殊的功能。
使用Method swizzling,寫法是基本相同的。比如說要給UIApplicationsendEvent:方法做交換,創(chuàng)建一個(gè)UIApplication的分類,在load方法中實(shí)現(xiàn)。

Method sendEventMethod = class_getInstanceMethod([self class], @selector(sendEvent:));
    Method sendNotifyEventMethod = class_getInstanceMethod([self class], @selector(my_sendEvent:));
    
    method_exchangeImplementations(sendEventMethod, sendNotifyEventMethod);

然后再寫一個(gè)你想用來替換系統(tǒng)sendEvent:實(shí)現(xiàn)的方法,在這個(gè)例子中叫做my_sendEvent:,然后再這個(gè)實(shí)現(xiàn)中調(diào)用自身。

- (void)my_sendEvent:(UIEvent *)event {
    
    NSLog(@"send evnet before %@",event);
    
    [self my_sendEvent:event];
    
    NSLog(@"send event after %@",event);
}

按照日常寫代碼的經(jīng)驗(yàn),在方法中調(diào)用自己,這不寫成死循環(huán)了嗎。但在這里,卻并不會(huì)形成循環(huán)。這是因?yàn)槲覀冊(cè)谏厦嬲{(diào)用了method_exchangeImplementations方法,將方法名和方法的實(shí)現(xiàn)進(jìn)行了交換,當(dāng)系統(tǒng)調(diào)用sendEvent:方法時(shí),調(diào)用到了my_sendEvent:的實(shí)現(xiàn)中,這時(shí)候我就可以做我想要的處理,并在這個(gè)方法中調(diào)用my_sendEvent:方法,但其實(shí)調(diào)用的實(shí)現(xiàn)是系統(tǒng)的sendEvent:,這樣可以在完成系統(tǒng)實(shí)現(xiàn)的基礎(chǔ)上完成了自己想要的邏輯。

  • 在這個(gè)方法中打斷點(diǎn)也可以看到_cmdsendEvnet:而不是my_sendEvent:

特殊寫法

前幾日在看到AFNetworking源碼的時(shí)候突然想起之前看的某篇博客說AFNetworkingdataTaskresume方法好像也是經(jīng)過方法交換的,想看一下它是怎么做的,是否是和我上面寫的一樣。于是就搜索了了一下method_exchangeImplementations方法,發(fā)現(xiàn)AFN并沒有通過分類實(shí)現(xiàn),于是我就看了下它的實(shí)現(xiàn)方法。

AFN的源碼看起來比較繞,但剝離方法的封裝之后,看起來就簡(jiǎn)單多了。比如想要交換上述的sendEvent:方法,并不需要寫在分類中,而是隨便寫了一個(gè)類,在這個(gè)類內(nèi)部處理。

+ (void)load {
    
    Method mySendEvent = class_getInstanceMethod([self class], @selector(my_sendEvent:));
    if(class_addMethod([UIApplication class], @selector(my_sendEvent:), method_getImplementation(mySendEvent), method_getTypeEncoding(mySendEvent))) {
     
        Method originalMethod = class_getInstanceMethod([UIApplication class], @selector(sendEvent:));
        Method swizzlingMethod = class_getInstanceMethod([UIApplication class], @selector(my_sendEvent:));
        method_exchangeImplementations(originalMethod, swizzlingMethod);   
    }    
}

- (void)my_sendEvent:(UIEvent *)event {
    
    [self my_sendEvent:event];
}

與之前的寫法大致相同,唯一不同的是,將自己的實(shí)現(xiàn)方法my_sendEvent:寫在了這個(gè)類中,并將這個(gè)方法用class_addMethod添加給了UIApplication。在自己的方法中打斷點(diǎn)可以發(fā)現(xiàn),這里的self并不是這個(gè)類的對(duì)象,而是UIApplication的對(duì)象。這個(gè)涉及到了OC底層objc_msgSend方法的原理,在這里就不細(xì)說了。

最后編輯于
?著作權(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)容