《Effective Objective-C 2.0 》 閱讀筆記 item13

第13條:用“方法調(diào)配技術(shù)”調(diào)試“黑盒方法”

1. 方法調(diào)配技術(shù)

既不需要源代碼,也不需要通過(guò)繼承子類(lèi)來(lái)覆寫(xiě)方法就能改變這個(gè)類(lèi)本身的功能。這樣一來(lái),新功能將在本類(lèi)的所有實(shí)例中生效,而不是僅限于覆寫(xiě)了相關(guān)方法的那些子類(lèi)實(shí)例。此方案經(jīng)常稱(chēng)為“方法調(diào)配”(method swizzling)。

2. 原理

類(lèi)的方法列表會(huì)把選擇器的名稱(chēng)映射到相關(guān)的方法實(shí)現(xiàn)之上,使得“動(dòng)態(tài)消息派發(fā)系統(tǒng)”能夠據(jù)此找到應(yīng)該調(diào)用的方法。這些方法均以函數(shù)指針(IMP)的形式來(lái)表示,其原型如下:

id (*IMP)(id, SEL, ...)

NSString類(lèi)的選擇器映射表 圖例:

Snip20160309_4.png

Objective-C運(yùn)行時(shí)系統(tǒng)提供的幾個(gè)方法都能夠用來(lái)操作這種表。開(kāi)發(fā)者可以向其中新增選擇器,也可以改變某選擇器所對(duì)應(yīng)的方法實(shí)現(xiàn),還可以交換兩個(gè)選擇器所映射的指針。

  • Method class_getInstanceMethod(Class aClass, SEL aSelector) :根據(jù)給定的選擇器從類(lèi)中取出與之相關(guān)的方法。
  • void method_exchangeImplementations( Method m1, Method m2):可以交換兩個(gè)方法實(shí)現(xiàn)

3. 應(yīng)用案例

編寫(xiě)一個(gè)方法,在此方法中實(shí)現(xiàn)所需的附加功能,并調(diào)用原有實(shí)現(xiàn)。
分類(lèi) NSString (EOCMyAdditions)頭文件:

@interface NSString (EOCMyAdditions)
- (NSString*)eoc_myLowercaseString;
@end

分類(lèi) NSString (EOCMyAdditions)實(shí)現(xiàn)文件:

@implementation NSString (EOCMyAdditions)
// 新增一個(gè)方法,實(shí)現(xiàn)附加功能
- (NSString *)eoc_myLowercaseString{
    NSString *lowercase = [self eoc_myLowercaseString];
    NSLog(@"%@ => %@", self, lowercase);
    return lowercase;
}
@end

main函數(shù):

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "NSString+EOCMyAdditions.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 1.交換方法
        Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
        Method swappedMethod = class_getInstanceMethod([NSString class], @selector(eoc_myLowercaseString));
        // 2.交換方法
        method_exchangeImplementations(originalMethod, swappedMethod);
        
        // 3.調(diào)用lowercaseString方法,但實(shí)現(xiàn)的功能卻是分類(lèi)中新增方法的附加功能
        NSString *string = @"THIs is tHe StRiNg";
        NSString *lowercaseString = [string lowercaseString];
        
    }
    return 0;
}

輸出結(jié)果:

 THIs is tHe StRiNg => this is the string

總結(jié):通過(guò)此方案,開(kāi)發(fā)者可以為那些“完全不知道其具體實(shí)現(xiàn)的”黑盒方法增加日志記錄功能,這非常有助于程序調(diào)試。然而,此做法只在調(diào)試程序時(shí)有用,禁止濫用。

要點(diǎn)

  • 運(yùn)行期,可以向類(lèi)中新增或替換選擇器所對(duì)應(yīng)的方法實(shí)現(xiàn)。
  • 使用另一份實(shí)現(xiàn)來(lái)替換原有的方法實(shí)現(xiàn),這道工序叫做“方法調(diào)配”,開(kāi)發(fā)者常用此技術(shù)向原有實(shí)現(xiàn)中添加新功能。
  • 一般來(lái)說(shuō),只有調(diào)試程序的時(shí)候才需要在運(yùn)行期修改方法實(shí)現(xiàn),這種做法不宜濫用。
最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 寫(xiě)在最前面: 這是我讀這本書(shū)的第一遍,目前暫定為1.0版本吧。很多地方都還沒(méi)有很好的理解透徹,只是理解到了一點(diǎn)皮毛...
    LaiYoung_閱讀 1,955評(píng)論 4 18
  • 聲明:這個(gè)筆記的系列是我每天早上打開(kāi)電腦第一件做的事情,當(dāng)然使用的時(shí)間也不是很多因?yàn)檫€有其他的事情去做,雖然吧自己...
    iSuAbner閱讀 892評(píng)論 2 16
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,688評(píng)論 19 139
  • 我的眼睛想必是出了故障 因?yàn)椴还鼙犙坶]眼 看見(jiàn)的全都是你
    陳芫閱讀 192評(píng)論 0 0
  • 我想,最可怕的不是二十多年來(lái)一直單身,而是嘗到了伴侶之間相互依偎的甜蜜,就再也無(wú)法觸碰單身的苦澀。 但是最后,我還...
    碳拾閱讀 312評(píng)論 0 1

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