object c runtime 經典講解系列二

2021-07-02 20:46:12 字數 3692 閱讀 6022

介紹乙個技巧,最好的方式就是提出具體的需求,然後用它跟其他的解決方法做比較。

@implementation

- (void)mybuttonclicked:(id)sender

這種方式的缺點也很明顯:它破壞了**的乾淨整潔。因為logging的**本身並不屬於viewcontroller裡的主要邏輯。隨著專案擴大、**量增加,你的viewcontroller裡會到處散布著logging的**。這時,要找到一段事件記錄的**會變得困難,也很容易忘記新增事件記錄的**。

你可能會想到用繼承或類別,在重寫的方法裡新增事件記錄的**。**可以是長的這個樣子:

@implementation

- (void)mybuttonclicked:(id)sender

logging的**都很相似,通過繼承或類別重寫相關方法是可以把它從主要邏輯中剝離出來。但同時也帶來新的問題:

你需要繼承uiviewcontroller,uitableviewcontroller,uicollectionviewcontroller所有這些 viewcontroller ,或者給他們新增類別; 

每個 viewcontroller 裡的 buttonclick 方法命名不可能都一樣; 

你不能控制別人如何去例項化你的子類; 

對於類別,你沒辦法呼叫到原來的方法實現。大多時候,我們重寫乙個方法只是為了新增一些**,而不是完全取代它。 

如果有兩個類別都實現了相同的方法,執行時沒法保證哪乙個類別的方法會給呼叫。

method swizzling 利用 runtime 特性把乙個方法的實現與另乙個方法的實現進行替換。

首先定義乙個類別,新增將要 swizzled 的方法:

@implementation

}

接下來實現 swizzle 的方法 :

@implementation uiviewcontroller (logging) void

swizzlemethod

(class class, sel originalselector, sel swizzledselector)

else

}

這裡唯一可能需要解釋的是class_addmethod。要先嘗試新增原 selector 是為了做一層保護,因為如果這個類沒有實現originalselector,但其父類實現了,那class_getinstancemethod會返回父類的方法。這樣method_exchangeimplementations替換的是父類的那個方法,這當然不是你想要的。所以我們先嘗試新增orginalselector,如果已經存在,再用method_exchangeimplementations把原方法的實現跟新的方法實現給交換掉。

@implementation

uiviewcontroller (logging) + (void)load

一般情況下,類別裡的方法會重寫掉主類裡相同命名的方法。如果有兩個類別實現了相同命名的方法,只有乙個方法會被呼叫。但+load:是個特例,當乙個類被讀到記憶體的時候, runtime 會給這個類及它的每乙個類別都傳送乙個+load:訊息。

其實,這裡還可以更簡化點:直接用新的 imp 取代原 imp ,而不是替換。只需要有全域性的函式指標指向原 imp 就可以。

}+ (void)load}

通過 method swizzling ,我們成功把邏輯**跟處理事件記錄的**解耦。當然除了 logging ,還有很多類似的事務,如 authentication 和 caching。這些事務瑣碎,跟主要業務邏輯無關,在很多地方都有,又很難抽象出來單獨的模組。這種程式設計問題,業界也給了他們乙個名字 - cross cutting concerns。

而像上面例子用 method swizzling 動態給指定的方法新增**,以解決 cross cutting concerns 的程式設計方式叫:aspect oriented programming

wikipedia 裡對 aop 是這麼介紹的:

在 objective-c 的世界裡,這句話意思就是利用 runtime 特性給指定的方法新增自定義**。有很多方式可以實現 aop ,method swizzling 就是其中之一。而且幸運的是,目前已經有一些第三方庫可以讓你不需要了解 runtime ,就能直接開始使用 aop 。

aspects 就是乙個不錯的 aop 庫,封裝了 runtime , method swizzling 這些黑色技巧,只提供兩個簡單的api:

+ (id

)aspect_hookselector

:(sel)selector

withoptions

:(aspectoptions)options

usingblock

:(id)block

error

:(nserror **)error; - (id

)aspect_hookselector

:(sel)selector

withoptions

:(aspectoptions)options

usingblock

:(id)block

error

:(nserror **)error;

使用 aspects 提供的 api,我們之前的例子會進化成這個樣子:

@implementation

uiviewcontroller (logging) + (void)load

error:null];

}

你可以用同樣的方式在任何你感興趣的方法裡新增自定義**,比如 ibaction 的方法裡。更好的方式,你提供乙個 logging 的配置檔案作為唯一處理事件記錄的地方:

@implementation

, },

@,},

],}, @"detailviewcontroller": @

};}+ (void)setupwithconfiguration:(nsdictionary *)configs

withoptions:aspectpositionafter

usingblock:^(id

aspectinfo) error:null]; // hook events

for (nsstring *classname in configs) error:null];}}

}}

yes;

} 利用 objective-c runtime 特性和 aspect oriented programming ,我們可以把瑣碎事務的邏輯從主邏輯中分離出來,作為單獨的模組。它是對物件導向程式設計模式的乙個補充。logging 是個經典的應用,這裡做個拋磚引玉,發揮想象力,可以做出其他有趣的應用。

使用 aspects 完整的例子可以從這裡獲得:aspectsdemo。

NOKIA筆經 面經

今天應該是畢業找工作生涯的最後一次面試了,發個筆經面經,為後來人 鋪路.我面的是radio network planning。筆試 海選,通過chinahr出的一組能力測試題篩選。好像篩了不少人。題目包括詞語填空,閱讀理解,圖形,數字題,基本數學題,題。一面 面試官為應聘職位的部門經理。基本上為中文...

面經和菜經

tencent面經 面試前一天晚上要休息好,精神養好 提前準備充足,包括服裝,簡歷,了解好公司的相關資訊 找工作一定要定位好合適的工作,把握不大的不要過去浪費時間 面試的時候一定不能緊張,回答問題一定要有明晰的思路 炸丸子經 所有材料事先備好,一切準備妥當,規劃好攪拌的順序 用筷子夾麵糰的時候,要用...

面經 葫蘆面經

1 給定乙個n位數,例如12345,從裡面去掉k個數字,得到乙個n k位的數,例如去掉2,4,得到135,去掉1,5,得到234。設計演算法,求出所有得到的 n k位數裡面最小的那乙個 2 找明星 n個人中,只有乙個明星 明星不認識其他所有的人,而其他人 都認識明星,這些人中也可能相互認識。你每次只...