首先要知道咱們寫的代碼在程序運行過程當中都會被轉化成runtime的C代碼執行。緩存
runtime突出的一點就是OC中消息傳遞機制的應用。objc_msgsend(target,SEL);設計
首先咱們先看一下runtime的定義文件指針
OC中的一切都被設計爲了對象,這些對象在Runtime中用struct(結構體)來表示。對象
下面來看一下runtime的經常使用功能獲取類的系列列表blog
定義以下一個類:get
方法調用在runtime(運行時)的調用過程,例如【self way】在runtime中會被轉化爲 objc_msgSend(self, @selector( way )).it
若是用實例對象調用實例方法,那麼系統回到實例對象的 isa 指針指向的對象中找到該方法進行操做。io
若是用類調用類方法,那麼系統回到類對象的 isa 指針指向的對象中操做。變量
在對象中找方法的時候,首先要在isa指針指向的對象中的緩存方法列表中找該方法,若是找到直接拿來用,反之若是沒有找到,那麼接着會到該對象的方法列表中找,若是找到直接拿來用,若是沒有找到,那麼就去對象的父類的isa指針中指向的對象中找,找的過程仍是跟上面同樣,先從緩存中找。若是一直都沒有找到該方法,那麼就要轉到攔截調用方法了(NSobjct對象中的方法),若是沒有實現攔截方法,那麼程序就會報錯。打包
總結出來就是,當調用方法的時候,會進行如下操做:
一、 從自己的isa指針所指對象的緩存方法中找,若是找到直接轉向相應的方法實現,若是沒有找到轉向2
二、從對象的方法列表中找,若是找到直接用,若是沒有找到轉向3
三、從對象的父類的isa指針所指的對象的緩存方法中找,若是找到直接轉向方法的實現,沒有的話轉向4
四、從父類isa指針所指對象的方法列表中找,若是找到直接轉向方法的實現,沒有的話轉向5
五、到超父類尚未找到的話,就須要轉到攔截調用啦。
六、若是攔截調用方法沒用實現的話程序就要報錯了。
攔截調用就是當沒有找到調用的方法的時候會轉向攔截調用(NSObjec對象中的方法)
攔截調用通常都是經過下面四個方法來實現的
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
這個方法是把你調用的不存在的方法重定向到一個其餘聲明瞭這個方法的淚,只須要你返回一個有這個方法的target
這個方法是把你調用的不存在的方法打包成NSInvocation傳給你,作完本身的處理後調用 invokeWithTarget:方法讓某個targer觸發這個方法。
這個方法是當你調用一個不存在的類方法的時候,會調用這個方法,能夠在這裏加上本身的處理而後返回YES,這裏默認是返回NO的;
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
這個方法是當你調用一個不存在的實例方法的時候觸發的;
當調用一個不存在的方法的時候,被攔截到後,若是不處理,仍然是沒有改方法的,程序仍然會出錯。
有一個方法是根據傳進來的SEL的類型來動態的添加方法的。
4個參數分別表示
Class cls 給哪一個類添加方法
SEL name 添加的方法
IMP imp 方法的實現,C方法的實現能夠直接獲取,OC的方法實現須要調用+(IMP)instanceMethodForSelector:(SEL)aSelector 來調用方法
「v@:*」方法的簽名,表明有一個參數的方法