SwizzleMethod的黑魔法

    void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
    {
        // the method might not exist in the class, but in its superclass
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        // class_addMethod will fail if original method already exists
        BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        
        // the method doesn’t exist and we just added one
        if (didAddMethod) {
            class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }
        else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }

上面這個(gè)C風(fēng)格函數(shù),就是SwizzleMethod的核心方法,用來(lái)交換Runtime中類和對(duì)象的方法接口指針。但是這有什么用呢?

你知道有名的第三方庫(kù)IQKeyboard么?

這個(gè)吊庫(kù),不需要引入頭文件,不需要調(diào)用任何方法就能使用。怎么做到的呢?
答案是NSObject的 + (void)load方法。

這個(gè)類方法,在軟件運(yùn)行時(shí)一定會(huì)調(diào)用一次,并且不需要調(diào)用super方法,因?yàn)楦割惖膌oad方法也一定會(huì)調(diào)用。

IQKeyboard就是在load方法中初始化的。

SwizzleMethod應(yīng)用實(shí)例 —— 無(wú)痛手術(shù)

這個(gè)比喻并不準(zhǔn)確,準(zhǔn)確說(shuō)應(yīng)該是無(wú)痕手術(shù) —— 對(duì)方法的無(wú)痕手術(shù)

+ (void)load
{
    swizzleMethod([AppDelegate class], @selector(application:didFinishLaunchingWithOptions:), @selector(swizzle_application:didFinishLaunchingWithOptions:));
}

這里,我們把AppDelegate的啟動(dòng)方法更換成了我們自己的swizzle_application:didFinishLaunchingWithOptions方法。兩個(gè)方法指針互換,然后我們?cè)谖覀兊姆椒ㄖ屑尤胛覀冃枰拇a。

- (BOOL)swizzle_application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //我們需要添加的代碼
    //
    return [self swizzle_application:application didFinishLaunchingWithOptions:launchOptions];
}

注意到了么,結(jié)尾我們自己調(diào)用swizzle_application:application方法,因?yàn)檫@個(gè)這個(gè)方法指針實(shí)際已經(jīng)指向AppDelegateapplication:didFinishLaunchingWithOptions方法。其他地方掉用AppDelegateapplication:didFinishLaunchingWithOptions方法則會(huì)指向我們的swizzle_application:application方法,這樣我們就在人不知不覺(jué)中,向AppDelegate插入了一段代碼,這一切不需要AppDelegate引入任何頭文件,是不是很Cool?

這樣一來(lái)就可以把需要放在這里面的各種監(jiān)測(cè)代碼初始化,都放到我們的swizzle_application:application方法中,可以給這個(gè)方法新建一個(gè)類,每次新建工程直接拖進(jìn)來(lái)一起編譯,分分鐘植入,帥爆一切,點(diǎn)個(gè)贊吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,775評(píng)論 0 9
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,947評(píng)論 18 139
  • 應(yīng)用啟動(dòng)時(shí)間,直接影響用戶對(duì)一款應(yīng)用的判斷和使用體驗(yàn)。頭條主app本身就包含非常多并且復(fù)雜度高的業(yè)務(wù)模塊(如新聞、...
    hgl閱讀 448評(píng)論 0 0
  • 基礎(chǔ) 1. 為什么說(shuō)Objective-C是一門動(dòng)態(tài)的語(yǔ)言? 2. 講一下MVC和MVVM,MVP? 3. 為...
    波妞和醬豆子閱讀 3,355評(píng)論 0 46
  • 首先得承認(rèn)一點(diǎn)的是,我并不是一個(gè)很好的記憶者,我最善于的事情就是忘記。因?yàn)槲視r(shí)常覺(jué)得忘記過(guò)往有利于行走于未來(lái)...
    兮說(shuō)星辰閱讀 356評(píng)論 0 1