iOS之規(guī)范2

iOS之規(guī)范2

參考鏈接:參考1撑帖,參考2參考3

類對(duì)象的結(jié)構(gòu)


struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
    
    //isa 指針:指向 Meta Class肿孵。類亦是一個(gè)對(duì)象
    //當(dāng)執(zhí)行[NSObject alloc]時(shí)唠粥,實(shí)際是把該消息發(fā)給類對(duì)象

#if !__OBJC2__
    Class super_class       //父類                                        OBJC2_UNAVAILABLE;
    const char *name        //類名                                         OBJC2_UNAVAILABLE;
    long version            //類的版本信息(默認(rèn):0)                                             OBJC2_UNAVAILABLE;
    long info       //類信息(供運(yùn)行時(shí)使用的一些位標(biāo)識(shí))                                                OBJC2_UNAVAILABLE;
    long instance_size      //類的實(shí)例標(biāo)量大小                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars        //類的成員變量鏈表                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists       //類的方法定義鏈表                   OBJC2_UNAVAILABLE;
    struct objc_cache *cache        //方法緩存(對(duì)象接到消息,isa 指向類對(duì)象停做。會(huì)找cache晤愧,后查找方法鏈表)                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols        //協(xié)議鏈表                    OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

objc在向一個(gè)對(duì)象發(fā)送消息時(shí):

  1. runtime庫會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的類,然后在該類中的方法列表(先找 cache)-> 然后其父類方法列表中尋找方法運(yùn)行蛉腌。
  2. 然后在發(fā)送消息的時(shí)候官份,objc_msgSend方法不會(huì)返回值,所謂的返回內(nèi)容都是具體調(diào)用時(shí)執(zhí)行的烙丛。
  3. 那么舅巷,回到本題,如果向一個(gè)nil對(duì)象發(fā)送消息河咽,首先在尋找對(duì)象的isa指針時(shí)就是0地址返回了钠右,所以不會(huì)出現(xiàn)任何錯(cuò)誤。

一個(gè) objc 對(duì)象如何進(jìn)行內(nèi)存布局(有父類)忘蟹?

  • 存儲(chǔ)空間:父類和自己的成員變量

  • isa 指針:指向類對(duì)象飒房。

    類對(duì)象中存放對(duì)象可操作的對(duì)象方法列表搁凸、成員變量列表屬性列表狠毯。

    類對(duì)象內(nèi)部也有一個(gè) isa指針:指向其元類(Meta Class:存放類方法列表护糖;superclass 指針:指向其父元類)

總結(jié):

  • <mark>OC 對(duì)象結(jié)構(gòu)組成:ISA 指針 + 根類實(shí)例變量 + …… + 父類實(shí)例變量 + 自身類實(shí)例變量。

OC對(duì)象 isa 指向類對(duì)象

類對(duì)象:isa 指向元類嚼松;superclass 指向父元類嫡良。

根元類:isa 指向自己;superclass 指向 NSObject 類惜颇。

objc中向一個(gè)nil 對(duì)象發(fā)送消息將發(fā)生什么皆刺?

答案:完全有效少辣,只是在運(yùn)行時(shí)不會(huì)有任何作用凌摄。

OC 是動(dòng)態(tài)語言,每個(gè)方法在運(yùn)行時(shí)會(huì)被動(dòng)態(tài)的轉(zhuǎn)為消息發(fā)送漓帅。即objc_msgSend(receiver,selector).

關(guān)于方法返回值:

返回值是對(duì)象:返回 nil

返回值是指針類型:返回 sizeof(void *)锨亏、float,int 等標(biāo)量忙干,返回 0

返回值是結(jié)構(gòu)體:返回0.結(jié)構(gòu)體中各元素亦為0

返回值是未知器予,則返回亦是未定義的。

objc中向一個(gè)對(duì)象發(fā)送消息[obj foo]和objc_msgSend()函數(shù)之間有什么關(guān)系捐迫?

答案:[obj foo]動(dòng)態(tài)編譯之后就是objc_msgSend (obj乾翔,@selector(foo))方法的調(diào)用。

關(guān)于unrecognized selector的異常

答案:

objc在向一個(gè)對(duì)象發(fā)送消息時(shí)施戴,runtime庫會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬的類反浓,首先在 Class 中的緩存查找 IMP (沒緩存則初始化緩存),如果沒找到赞哗,然后在該類中的方法列表以及其父類方法列表中尋找方法運(yùn)行雷则。

如果一直查找到根類仍舊沒有實(shí)現(xiàn),則用_objc_msgForward函數(shù)指針代替 IMP 肪笋。最后月劈,執(zhí)行這個(gè) IMP 。

程序在運(yùn)行時(shí)會(huì)掛掉并拋出異常unrecognized selector sent to XXX 藤乙。

但是在這之前猜揪,objc的運(yùn)行時(shí)會(huì)給出三次拯救程序崩潰的機(jī)會(huì)(_objc_msgForward函數(shù)的轉(zhuǎn)發(fā)功能):

  1. Method resolution

    調(diào)用resolveInstanceMethod:方法 (或 resolveClassMethod:)。允許用戶在此時(shí)為該 Class 動(dòng)態(tài)添加實(shí)現(xiàn)坛梁。如果有實(shí)現(xiàn)了而姐,則調(diào)用并返回YES,那么重新開始o(jì)bjc_msgSend流程罚勾。這一次對(duì)象會(huì)響應(yīng)這個(gè)選擇器毅人,一般是因?yàn)樗呀?jīng)調(diào)用過class_addMethod吭狡。如果仍沒實(shí)現(xiàn),繼續(xù)下面的動(dòng)作丈莺。

    + (BOOL)resolveInstanceMethod:(SEL)sel __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0)
     {
        class_addMethod(self.class, sel, (IMP)dynamicMethodIMP, "@@:");
        BOOL rslt = [super resolveInstanceMethod:sel];
        rslt = YES;
        return rslt; // 1
    

}

```
  1. Fast forwarding

    調(diào)用forwardingTargetForSelector:方法划煮,嘗試找到一個(gè)能響應(yīng)該消息的對(duì)象。如果獲取到缔俄,則直接把消息轉(zhuǎn)發(fā)給它弛秋,返回非 nil 對(duì)象。否則返回 nil 俐载,繼續(xù)下面的動(dòng)作蟹略。注意,這里不要返回 self 遏佣,否則會(huì)形成死循環(huán)挖炬。

    - (id)forwardingTargetForSelector:(SEL)aSelector __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0) 
    {
        id rslt = [super forwardingTargetForSelector:aSelector];
        rslt = self.target;
        return rslt; // 2
    

}
```

  1. Normal forwarding

    調(diào)用methodSignatureForSelector:方法,嘗試獲得一個(gè)方法簽名状婶。如果獲取不到意敛,則直接調(diào)用doesNotRecognizeSelector拋出異常。如果能獲取膛虫,則返回非nil:創(chuàng)建一個(gè) NSlnvocation 并傳給forwardInvocation草姻。

    調(diào)用forwardInvocation:方法,將上面獲取到的方法簽名包裝成 Invocation 傳入稍刀,如何處理就在這里面了撩独,并返回非ni。

    //OBJC_SWIFT_UNAVAILABLE("")
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    

{
id rslt = [super methodSignatureForSelector:aSelector];
NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:"v@:"];
rslt = sig;
return rslt; // 3
}
//OBJC_SWIFT_UNAVAILABLE("")

  • (void)forwardInvocation:(NSInvocation *)anInvocation
    {
    // [super forwardInvocation:anInvocation];
    [self.target forwardInvocation:anInvocation];
    }
```
> 調(diào)用doesNotRecognizeSelector: 账月,默認(rèn)的實(shí)現(xiàn)是拋出異常综膀。如果上面沒能獲得一個(gè)方法簽名,執(zhí)行該步驟捶障。

```
- (void)doesNotRecognizeSelector:(SEL)aSelector {
// 在crash前 保存crash數(shù)據(jù)僧须,供分析

[super doesNotRecognizeSelector:aSelector]; // crash

}

```

總結(jié):上面的方法均是模板方法,開發(fā)者可以override项炼,由 runtime 來調(diào)用担平。最常見的實(shí)現(xiàn)消息轉(zhuǎn)發(fā):就是重寫方法3,吞掉一個(gè)消息或者代理給其他對(duì)象都是沒問題的锭部。

附:_objc_msgForward直接調(diào)用最佳實(shí)踐:《JSPatch實(shí)現(xiàn)原理詳解》

有關(guān) runtime 鏈接

runtime 如何通過 selector 找到對(duì)應(yīng)的 IMP 地址暂论?(類方法和實(shí)例方法)

答案:

每一個(gè)類對(duì)象中都一個(gè)方法列表,方法列表中記錄著方法的名稱,方法實(shí)現(xiàn),以及參數(shù)類型,其實(shí)selector本質(zhì)就是方法名稱,通過這個(gè)方法名稱就可以在方法列表中找到對(duì)應(yīng)的方法實(shí)現(xiàn).

使用runtime Associate方法關(guān)聯(lián)的對(duì)象,需要在主對(duì)象dealloc的時(shí)候釋放么拌禾?

答:MRC 和 ARC 下均不需要取胎。

對(duì)象銷毀后,被關(guān)聯(lián)的對(duì)象就會(huì)被釋放了

具體的時(shí)間:被關(guān)聯(lián)的對(duì)象在生命周期內(nèi)要比對(duì)象本身釋放的晚很多。它們會(huì)在被 NSObject -dealloc 調(diào)用的 object_dispose() 方法中釋放

對(duì)象的內(nèi)存銷毀時(shí)間表:

  1. 調(diào)用 -release :引用計(jì)數(shù)變?yōu)榱?
    • 對(duì)象正在被銷毀闻蛀,生命周期即將結(jié)束.
    • 不能再有新的 __weak 弱引用匪傍, 否則將指向 nil.
    • 調(diào)用 [self dealloc]
  2. 父類 調(diào)用 -dealloc
    • 繼承關(guān)系中最底層的父類 在調(diào)用 -dealloc
    • 如果是 MRC 代碼 則會(huì)手動(dòng)釋放實(shí)例變量們(iVars)
    • 繼承關(guān)系中每一層的父類 都在調(diào)用 -dealloc
  3. NSObject 調(diào) -dealloc
    • 只做一件事:調(diào)用 Objective-C runtime 中的 object_dispose() 方法
  4. 調(diào)用 object_dispose()
    • 為 C++ 的實(shí)例變量們(iVars)調(diào)用 destructors
    • 為 ARC 狀態(tài)下的 實(shí)例變量們(iVars) 調(diào)用 -release
    • 解除所有使用 runtime Associate方法關(guān)聯(lián)的對(duì)象
    • 解除所有 __weak 引用
    • 調(diào)用 free()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市觉痛,隨后出現(xiàn)的幾起案子役衡,更是在濱河造成了極大的恐慌,老刑警劉巖薪棒,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件手蝎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡俐芯,警方通過查閱死者的電腦和手機(jī)棵介,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吧史,“玉大人邮辽,你說我怎么就攤上這事】垓撸” “怎么了逆巍?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵及塘,是天一觀的道長莽使。 經(jīng)常有香客問我,道長笙僚,這世上最難降的妖魔是什么芳肌? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮肋层,結(jié)果婚禮上亿笤,老公的妹妹穿的比我還像新娘。我一直安慰自己栋猖,他們只是感情好净薛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蒲拉,像睡著了一般肃拜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雌团,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天燃领,我揣著相機(jī)與錄音,去河邊找鬼锦援。 笑死猛蔽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播曼库,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼区岗,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了毁枯?” 一聲冷哼從身側(cè)響起躏尉,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎后众,沒想到半個(gè)月后胀糜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒂誉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年教藻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片右锨。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡括堤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绍移,到底是詐尸還是另有隱情悄窃,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布蹂窖,位于F島的核電站轧抗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瞬测。R本人自食惡果不足惜横媚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望月趟。 院中可真熱鬧灯蝴,春花似錦、人聲如沸孝宗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽因妇。三九已至问潭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沙峻,已是汗流浹背睦授。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摔寨,地道東北人去枷。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親删顶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子竖螃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,715評(píng)論 0 9
  • 我在之前的讀后感中說過我們每個(gè)人自己就是“我”這家無限責(zé)任公司的老板逗余,那么我們最親近的家人——配偶特咆、父母、子...
    昕夕逐浪閱讀 255評(píng)論 2 1
  • 一切可以妥當(dāng)?shù)囊欢〞?huì)妥當(dāng)录粱!準(zhǔn)備迎接奇跡腻格!很喜歡的話送給眾生! 簡(jiǎn)單想啥繁,認(rèn)真行菜职! 我近期目標(biāo)是財(cái)富增長!愿景是希望通...
    belivePossible閱讀 121評(píng)論 0 1
  • 壞心情也會(huì)惡性循環(huán)旗闽,想要快速終止酬核,就要好心情來填滿;有時(shí)候難過并不是真的失去什么适室,而是得而復(fù)失的體驗(yàn)嫡意,是希望之后的...
    Mayday海星閱讀 234評(píng)論 0 0
  • 我有一個(gè)關(guān)系很好的姐姐,騰訊名叫姑涼捣辆。 她性格不拘小節(jié)蔬螟,常常與男孩子混一起,偏偏生了一副好模樣罪帖。自...
    小仙女叫璃沫沫嘿閱讀 324評(píng)論 0 0