Swizzling應(yīng)該總是在+load中執(zhí)行
在Objective-C中减宣,運(yùn)行時(shí)會(huì)自動(dòng)調(diào)用每個(gè)類的兩個(gè)方法。+load會(huì)在類初始加載時(shí)調(diào)用,+initialize會(huì)在第一次調(diào)用類的類方法或?qū)嵗椒ㄖ氨徽{(diào)用。這兩個(gè)方法是可選的,且只有在實(shí)現(xiàn)了它們時(shí)才會(huì)被調(diào)用擦耀。由于method swizzling會(huì)影響到類的全局狀態(tài),因此要盡量避免在并發(fā)處理中出現(xiàn)競爭的情況涩堤。+load能保證在類的初始化過程中被加載眷蜓,并保證這種改變應(yīng)用級(jí)別的行為的一致性。相比之下胎围,+initialize在其執(zhí)行時(shí)不提供這種保證—事實(shí)上吁系,如果在應(yīng)用中沒為給這個(gè)類發(fā)送消息,則它可能永遠(yuǎn)不會(huì)被調(diào)用白魂。
Swizzling應(yīng)該總是在dispatch_once中執(zhí)行
因?yàn)閟wizzling會(huì)改變?nèi)譅顟B(tài)汽纤,所以我們需要在運(yùn)行時(shí)采取一些預(yù)防措施.GCD的dispatch_once可以確保這種行為,我們應(yīng)該將其作為method swizzling的最佳實(shí)踐福荸。
選擇器蕴坪、方法與實(shí)現(xiàn)
選擇器(selector)、方法(method)和實(shí)現(xiàn)(implementation)是運(yùn)行時(shí)中一個(gè)特殊點(diǎn)
Selector(typedef struct objc_selector *SEL):
用于在運(yùn)行時(shí)中表示一個(gè)方法的名稱敬锐。一個(gè)方法選擇器是一個(gè)C字符串背传,它是在Objective-C運(yùn)行時(shí)被注冊的。選擇器由編譯器生成台夺,并且在類被加載時(shí)由運(yùn)行時(shí)自動(dòng)做映射操作径玖。
Method(typedef struct objc_method *Method):
在類定義中表示方法的類型
Implementation(typedef id (*IMP)(id, SEL, …)):
這是一個(gè)指針類型,指向方法實(shí)現(xiàn)函數(shù)的開始位置颤介。這個(gè)函數(shù)使用為當(dāng)前CPU架構(gòu)實(shí)現(xiàn)的標(biāo)準(zhǔn)C調(diào)用規(guī)范梳星。每一個(gè)參數(shù)是指向?qū)ο笞陨淼闹羔?self)赞赖,第二個(gè)參數(shù)是方法選擇器。然后是方法的實(shí)際參數(shù)冤灾。
注意事項(xiàng)
1 總是調(diào)用方法的原始實(shí)現(xiàn)前域。API提供了一個(gè)輸入與輸出約定,但其內(nèi)部實(shí)現(xiàn)是一個(gè)黑盒韵吨。Swizzle一個(gè)方法而不調(diào)用原始實(shí)現(xiàn)可能會(huì)打破私有狀態(tài)底層操作匿垄,從而影響到程序的其它部分。
2 避免沖突:給自定義的分類方法加前綴学赛,從而使其與所依賴的代碼庫不會(huì)存在命名沖突年堆。
3 明白是怎么回事
4 小心操作
理解這幾個(gè)術(shù)語之間的關(guān)系最好的方式是:一個(gè)類維護(hù)一個(gè)運(yùn)行時(shí)可接收的消息分發(fā)表吞杭;分發(fā)表中的每個(gè)入口是一個(gè)方法(Method)盏浇,其中key是一個(gè)特定名稱,即選擇器(SEL)芽狗,其對(duì)應(yīng)一個(gè)實(shí)現(xiàn)(IMP)绢掰,即指向底層C函數(shù)的指針。
為了swizzle一個(gè)方法童擎,我們可以在分發(fā)表中將一個(gè)方法的現(xiàn)有的選擇器映射到不同的實(shí)現(xiàn)滴劲,而將該選擇器對(duì)應(yīng)的原始實(shí)現(xiàn)關(guān)聯(lián)到一個(gè)新的選擇器中