Runtime之Method Swizzling

Method Swizzling

參考
原文:http://nshipster.com/method-swizzling/
譯文:http://nshipster.cn/method-swizzling/

Method swizzling is the process of changing the implementation of an existing selector. It’s a technique made possible by the fact that method invocations in Objective-C can be changed at runtime, by changing how selectors are mapped to underlying functions in a class’s dispatch table.

method swizzling用于改變一個已經(jīng)存在的selector的實(shí)現(xiàn).這項(xiàng)技術(shù)通過改變類的分發(fā)列表中selector與函數(shù)的映射關(guān)系,從而使OC可以在運(yùn)行時改變方法的調(diào)用.

例如:我們想要在一款 iOS app 中追蹤每一個視圖控制器被用戶呈現(xiàn)了幾次.這可以通過在每個視圖控制器的 viewDidAppear: 方法中添加追蹤代碼來實(shí)現(xiàn)蔑歌,但這樣會產(chǎn)生大量重復(fù)的樣板代碼算凿。繼承是另一種可行的方式雄嚣,但是這要求所有被繼承的視圖控制器如 UIViewController, UITableViewController, UINavigationController 都在 viewDidAppear:實(shí)現(xiàn)追蹤代碼菇绵,這同樣會造成很多重復(fù)代碼。 幸運(yùn)的是后雷,這里有另外一種可行的方式:利用category實(shí)現(xiàn)method swizzling.

#import <objc/runtime.h>

@implementation UIViewController (Tracking)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(viewWillAppear:);
        SEL swizzledSelector = @selector(xxx_viewWillAppear:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        // When swizzling a class method, use the following:
        // Class class = object_getClass((id)self);
        // ...
        // Method originalMethod = class_getClassMethod(class, originalSelector);
        // Method swizzledMethod = class_getClassMethod(class, swizzledSelector);

        BOOL didAddMethod =
            class_addMethod(class,
                originalSelector,
                method_getImplementation(swizzledMethod),
                method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                swizzledSelector,
                method_getImplementation(originalMethod),
                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

#pragma mark - Method Swizzling

- (void)xxx_viewWillAppear:(BOOL)animated {
    [self xxx_viewWillAppear:animated];
    NSLog(@"viewWillAppear: %@", self);
}

@end

+load vs. +initialize

Swizzling should always be done in +load.

There are two methods that are automatically invoked by the Objective-C runtime for each class. +load is sent when the class is initially loaded, while +initialize is called just before the application calls its first method on that class or an instance of that class. Both are optional, and are executed only if the method is implemented.

對于OC的每一個類,有兩個方法是由OC運(yùn)行時自動調(diào)用.一個是+load,另一個是+ initialize.+load是當(dāng)一個類初始裝載時被調(diào)用,+initialize是應(yīng)用在第一次調(diào)用該類的類方法或?qū)嵗椒ㄇ罢{(diào)用的吠各。這兩個方法是可選實(shí)現(xiàn)的,僅當(dāng)方法實(shí)現(xiàn)后才會被調(diào)用.

Selectors, Methods, & Implementations

In Objective-C, selectors, methods, and implementations refer to particular aspects of the runtime, although in normal conversation, these terms are often used interchangeably to generally refer to the process of message sending.

Here is how each is described in Apple’s Objective-C Runtime Reference:

  • Selector (typedef struct objc_selector *SEL): Selectors are used to represent the name of a method at runtime. A method selector is a C string that has been registered (or “mapped”) with the Objective-C runtime. Selectors generated by the compiler are automatically mapped by the runtime when the class is loaded .
  • Method (typedef struct objc_method *Method): An opaque type that represents a method in a class definition.
  • Implementation (typedef id (*IMP)(id, SEL, ...)): This data type is a pointer to the start of the function that implements the method. This function uses standard C calling conventions as implemented for the current CPU architecture. The first argument is a pointer to self (that is, the memory for the particular instance of this class, or, for a class method, a pointer to the metaclass). The second argument is the method selector. The method arguments follow.

The best way to understand the relationship between these concepts is as follows: a class (Class) maintains a dispatch table to resolve messages sent at runtime; each entry in the table is a method (Method), which keys a particular name, the selector (SEL), to an implementation (IMP), which is a pointer to an underlying C function.

To swizzle a method is to change a class’s dispatch table in order to resolve messages from an existing selector to a different implementation, while aliasing the original method implementation to a new selector.

翻譯:在 Objective-C 的運(yùn)行時中臀突,selectors, methods, implementations 指代了不同概念,但是通常,在消息發(fā)送過程中贾漏,這三個概念是可以相互轉(zhuǎn)換的候学。

  • Selector:SEL類型.在運(yùn)行時 Selectors 用來代表一個方法的名字。一個方法的selector就是一個C字符串,并且在運(yùn)行時被注冊(或映射)纵散。Selector由編譯器產(chǎn)生并且在當(dāng)類被加載進(jìn)內(nèi)存時由運(yùn)行時自動進(jìn)行名字和實(shí)現(xiàn)的映射梳码。
  • Method: Method類型.一種晦澀的類型,代表類中定義的一個方法.
  • Implementation:IMP類型,一個函數(shù)指針.指向方法實(shí)現(xiàn)的函數(shù)首地址.

三者之間的關(guān)系的最好理解方式如下:在運(yùn)行時一個類維護(hù)著一個用于解決消息發(fā)送的分發(fā)列表.列表中的每一個入口都是一個方法(Method),該方法映射了一個鍵值對,鍵是selector(SEL類型),值是一個實(shí)現(xiàn)(IMP),是一個函數(shù)指針,指向?qū)崿F(xiàn)對應(yīng)的C函數(shù).

Method Swizzling圖示(個人理解,可能并不準(zhǔn)確):


Method Swizzling圖說@2x.png

方法交換后,SELA映射到IMPB,而SELB映射到IMPA.以后,如果再對對象發(fā)送消息SELA,那么函數(shù)ImplementationB將會被執(zhí)行.類似的,對對象發(fā)送消息SELB,那么函數(shù)ImplementationA將會被執(zhí)行.

有人可能會覺得Method Swizzling好像也沒什么用啊.如果你只是Swizzling一下自己的類的方法確實(shí)沒什么卵用.但是如果你想要在系統(tǒng)的某個方法執(zhí)行之前或之后再執(zhí)行一些你的代碼.Method Swizzling就是一個好東西了,你可以寫一個自己的方法,然后通過Method Swizzling交換系統(tǒng)的方法.這樣以后給對象發(fā)送系統(tǒng)的某個消息,那么你的方法就會被執(zhí)行.

比如UITableView+FDTemplateLayoutCell第三方庫里清除cell緩存的高度的時機(jī),就是Method Swizzling了tableView的系統(tǒng)的reloadData等方法.而使用者卻無需關(guān)心清除時機(jī),也無需寫任何清緩存高度的代碼.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末隐圾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子掰茶,更是在濱河造成了極大的恐慌暇藏,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件濒蒋,死亡現(xiàn)場離奇詭異盐碱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)沪伙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門瓮顽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人围橡,你說我怎么就攤上這事暖混。” “怎么了翁授?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵拣播,是天一觀的道長。 經(jīng)常有香客問我黔漂,道長诫尽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任炬守,我火速辦了婚禮牧嫉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘减途。我一直安慰自己酣藻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布鳍置。 她就那樣靜靜地躺著辽剧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪税产。 梳的紋絲不亂的頭發(fā)上怕轿,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機(jī)與錄音辟拷,去河邊找鬼撞羽。 笑死,一個胖子當(dāng)著我的面吹牛衫冻,可吹牛的內(nèi)容都是我干的诀紊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼隅俘,長吁一口氣:“原來是場噩夢啊……” “哼邻奠!你這毒婦竟也來了笤喳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤碌宴,失蹤者是張志新(化名)和其女友劉穎杀狡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唧喉,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捣卤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了八孝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片董朝。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖干跛,靈堂內(nèi)的尸體忽然破棺而出子姜,到底是詐尸還是另有隱情,我是刑警寧澤楼入,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布哥捕,位于F島的核電站,受9級特大地震影響嘉熊,放射性物質(zhì)發(fā)生泄漏遥赚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一阐肤、第九天 我趴在偏房一處隱蔽的房頂上張望凫佛。 院中可真熱鬧,春花似錦孕惜、人聲如沸愧薛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毫炉。三九已至,卻和暖如春削罩,著一層夾襖步出監(jiān)牢的瞬間瞄勾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工弥激, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留进陡,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓秆撮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親换况。 傳聞我的和親對象是個殘疾皇子职辨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉盗蟆,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,721評論 0 9
  • Runtime 又叫運(yùn)行時,iOS 內(nèi)部的核心之一,底層的 為C 語言 寫的API舒裤,底層都是基于它來實(shí)現(xiàn)的喳资。在沒有...
    亂塵閱讀 599評論 0 0
  • 我們常常會聽說 Objective-C 是一門動態(tài)語言,那么這個「動態(tài)」表現(xiàn)在哪呢腾供?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,195評論 0 7
  • 今天準(zhǔn)備學(xué)習(xí)Objective-C Runtime相關(guān)知識仆邓,看到了Method Swizzling技術(shù),并找到了介...
    koce_zhao閱讀 441評論 0 2
  • 文/米衙 過去幾年伴鳖,我給無數(shù)人做了職業(yè)規(guī)劃节值。最近翻開一些筆記,總結(jié)出兩條經(jīng)驗(yàn)榜聂。 第一條是搞疗,能在職業(yè)生涯中取得成績的...
    米衙閱讀 627評論 1 6