iOS中級(jí)理論知識(shí)復(fù)習(xí)(Runtime篇)

在簡(jiǎn)書看到大牛的知識(shí)點(diǎn),發(fā)現(xiàn)很多知識(shí)點(diǎn)自己一知半解,能做項(xiàng)目但理論不夠扎實(shí),默默地去百度總結(jié)一下.放到這里和大家交流交流.

如有侵權(quán),告知即刪!


01.objc在向一個(gè)對(duì)象發(fā)送消息時(shí),發(fā)生了什么?

objective-c 的 Runtime 鑄就了它動(dòng)態(tài)語言的特性,這些深層次的知識(shí)雖然平時(shí)寫代碼用的少一些,但是卻是每個(gè) Objc 程序員需要了解的。
Objc Runtime使得C具有了面向?qū)ο竽芰?,在程序運(yùn)行時(shí)創(chuàng)建,檢查,修改類、對(duì)象和它們的方法。可以使用runtime的一系列方法實(shí)現(xiàn)。
附上OC中一個(gè)類的底層數(shù)據(jù)結(jié)構(gòu)

struct objc_class {
    Class isa OBJC_ISA_AVAILABILITY; //isa指針指向Meta Class,因?yàn)镺bjc的類的本身也是一個(gè)Object,為了處理這個(gè)關(guān)系,r       untime就創(chuàng)造了Meta Class,當(dāng)給類發(fā)送[NSObject alloc]這樣消息時(shí),實(shí)際上是把這個(gè)消息發(fā)給了Class Object

    #if !__OBJC2__
    Class super_class OBJC2_UNAVAILABLE; // 父類
    const char *name OBJC2_UNAVAILABLE; // 類名
    long version OBJC2_UNAVAILABLE; // 類的版本信息,默認(rèn)為0
    long info OBJC2_UNAVAILABLE; // 類信息,供運(yùn)行期使用的一些位標(biāo)識(shí)
    long instance_size OBJC2_UNAVAILABLE; // 該類的實(shí)例變量大小
    struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類的成員變量鏈表
    struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定義的鏈表
    struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法緩存,對(duì)象接到一個(gè)消息會(huì)根據(jù)isa指針查找消息對(duì)象,這時(shí)會(huì)在method       Lists中遍歷,如果cache了,常用的方法調(diào)用時(shí)就能夠提高調(diào)用的效率。
    struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協(xié)議鏈表
    #endif

    } OBJC2_UNAVAILABLE;

OC中一個(gè)類的對(duì)象實(shí)例的[數(shù)據(jù)結(jié)構(gòu)],就是定義了一個(gè)

typedef struct objc_class *Class;

    /// Represents an instance of a class.

    struct objc_object {

        Class isa  OBJC_ISA_AVAILABILITY;

    };

    /// A pointer to an instance of a class.

    typedef struct objc_object *id;

向object發(fā)送消息時(shí),Runtime庫(kù)會(huì)根據(jù)object的isa指針找到這個(gè)實(shí)例object所屬于的類,然后在類的方法列表以及父類方法列表尋找對(duì)應(yīng)的方法運(yùn)行。id是一個(gè)objc_object結(jié)構(gòu)類型的指針,這個(gè)類型的對(duì)象能夠轉(zhuǎn)換成任何一種對(duì)象。

然后再來看看消息發(fā)送的函數(shù):objc_msgSend函數(shù)
在引言中已經(jīng)對(duì)objc_msgSend進(jìn)行了一點(diǎn)介紹,看起來像是objc_msgSend返回了數(shù)據(jù),其實(shí)objc_msgSend從不返回?cái)?shù)據(jù)而是你的方法被調(diào)用后返回了數(shù)據(jù)。下面詳細(xì)敘述下消息發(fā)送步驟:
1.檢測(cè)這個(gè) selector 是不是要忽略的。比如 Mac OS X 開發(fā),有了垃圾回收就不理會(huì) retain,release 這些函數(shù)了。
2.檢測(cè)這個(gè) target 是不是 nil 對(duì)象。ObjC 的特性是允許對(duì)一個(gè) nil 對(duì)象執(zhí)行任何一個(gè)方法不會(huì) Crash,因?yàn)闀?huì)被忽略掉。
3.如果上面兩個(gè)都過了,那就開始查找這個(gè)類的 IMP,先從 cache 里面找,完了 找得到就跳到對(duì)應(yīng)的函數(shù)去執(zhí)行。
4.如果 cache 找不到就找一下方法分發(fā)表。
5.如果分發(fā)表找不到就到超類的分發(fā)表去找,一直找,直到找到NSObject類為止。
6.如果還找不到就要開始進(jìn)入動(dòng)態(tài)方法解析了,后面會(huì)提到。


02.什么時(shí)候會(huì)報(bào)unrecognized selector錯(cuò)誤?iOS有哪些機(jī)制來避免走到這一步?

當(dāng)調(diào)用對(duì)象的某個(gè)方法的時(shí)候, 如果在當(dāng)前類中沒有找到此方法, 那么就到當(dāng)前類的父類中去尋找, 如果在父類中沒有找到, 那么就去父類的父類中去尋找, 一直找到 NSObject 都沒有這個(gè)方法, 就會(huì)報(bào) Unrecognized selector 的異常.

但是在這之前, objc 的運(yùn)行時(shí)會(huì)給出三次拯救程序崩潰的機(jī)會(huì).

第一次: 動(dòng)態(tài)添加一個(gè)新方法并執(zhí)行的機(jī)會(huì)

[objc]

+ (bool)resolveInstanceMethod:(sel)sel{  
  
}  

當(dāng)系統(tǒng)第一次找不到某個(gè)方法的時(shí)候, 會(huì)自動(dòng)調(diào)用這個(gè)方法, 用來給程序添加一個(gè)新方法并執(zhí)行的機(jī)會(huì).
第二次: 當(dāng)系統(tǒng)調(diào)用上一個(gè)方法后未能實(shí)現(xiàn)添加新的方法, 則系統(tǒng)會(huì)再來調(diào)用下面的這個(gè)方法, 這個(gè)方法是系統(tǒng)提供的一個(gè)將 SEL 轉(zhuǎn)給其他對(duì)象的機(jī)會(huì)

[objc]

- (id)forwardingTargetForselector:(sel)aselctor{  
  
}  

第三次: 當(dāng) forwardingTargetForselector 返回的 nil 或者 self 時(shí), 會(huì)進(jìn)入到這個(gè)方法, 這個(gè)方法是拯救程序的最后一步.
這個(gè)方法用來返回一個(gè)方法簽名, 在由后面的 forwardInvocation: 去執(zhí)行

[objc]

- (NSMethodSigature *)methodSignatrueForseletor:(sel)aselector{  
  
}  

如果上面的方法不返回 nil, 則會(huì)來到這個(gè)方法里具體執(zhí)行

[objc]

-(void)forwardInvocation:(NSInvocation *)anInvocation{  
  
  在這里會(huì)調(diào)用自己對(duì)象的其他方法, 也可以調(diào)用其他函數(shù)  
  甚至還可以調(diào)用多個(gè)不同對(duì)象的多個(gè)方法  
  
 }  

03.runtime如何實(shí)現(xiàn)weak變量的自動(dòng)置nil?

要實(shí)現(xiàn) weak 屬性,首先要搞清楚 weak 屬性的特點(diǎn):

weak 此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系” (nonowning relationship)。為這種屬性設(shè)置新值時(shí),設(shè)置方法既不保留新值,也不釋放舊值。此特質(zhì)同 assign 類似, 然而在屬性所指的對(duì)象遭到摧毀時(shí),屬性值也會(huì)清空(nil out)。

那么 runtime 如何實(shí)現(xiàn) weak 變量的自動(dòng)置nil?

runtime 對(duì)注冊(cè)的類, 會(huì)進(jìn)行布局,對(duì)于 weak 對(duì)象會(huì)放入一個(gè) hash 表中。 用 weak 指向的對(duì)象內(nèi)存地址作為 key,當(dāng)此對(duì)象的引用計(jì)數(shù)為0的時(shí)候會(huì) dealloc,假如 weak 指向的對(duì)象內(nèi)存地址是a,那么就會(huì)以a為鍵, 在這個(gè) weak 表中搜索,找到所有以a為鍵的 weak 對(duì)象,從而設(shè)置為 nil。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,054評(píng)論 0 9
  • 在表單中我們會(huì)用到上傳文件的操作,現(xiàn)就文件相關(guān)API做以下總結(jié)。文件相關(guān)的對(duì)象主要有5個(gè)。 Blob對(duì)象: 是一個(gè)...
    tiancai啊呆閱讀 1,228評(píng)論 0 0
  • 一個(gè)好習(xí)慣可以受用一輩子。這樣的道理對(duì)于大多數(shù)人來說并不陌生。但養(yǎng)成一個(gè)習(xí)慣的過程并不容易。本書就是圍繞怎樣養(yǎng)成一...
    郭振南閱讀 482評(píng)論 0 0
  • 云若V閱讀 394評(píng)論 3 1
  • 明天冰雪封山的時(shí)候 我也光著雙腳站在你翻山越嶺的盡頭 正當(dāng)年少 ----宋冬野《鴿子》 愿你我既可以朝九晚五,又能...
    二兩_酋長(zhǎng)閱讀 631評(píng)論 0 2

友情鏈接更多精彩內(nèi)容