Runtime 常用場景(四)
1. Runtime 怎麼新增屬性、方法?
* ivar 表示成員變數
* class_addIvar
* class_addMethod
* class_addProperty
* class_addProtocol
* class_replacePropeerty
2.Runtime 如何實現 weak 屬性?
weak 策略表明該屬性定義了一種“非擁有關係”(nonowning reelationship)。為這種屬性設定新值時,設定方法既不保留新值,也不是放舊值。此特質和assign 雷西;然而在屬性所指的物件遭到毀滅時,屬性值也餓會清空(nil out)。
那麼 runtime 如何實現 weak 變數自動置 nil?
runtime 對註冊的類會進行佈局,將 weak 物件放入一個 hash 表中。用weak 指向的物件記憶體地址是a,那麼就會以a 為key,在這個 weak hash 表中搜索,找到所有以 a 為 key 的weak 物件,從而設定為 nil。
weak 屬性需要在dealloc 中設定nil 麼
在 ARC 環境中無論是強指標還是弱指標都無需在 dealloc 設定nil, ARC 會自動幫我們處理
即便是編譯器不幫我們做這些事情, weak 也不需要在 dealloc 中置 nil, 在屬性所致物件操刀摧毀時,屬性值也會清空!
3.runtime 如何通過 selector 找到對應的 IMP 地址?(分別考慮類方法和例項方法)
1.每一個類物件中都一個物件方法列表(物件方法快取)
2.類方法列表是存放在類物件中 isa 指標指向的元類物件中(類方法快取)
3.方法列表中每個方法結構體中記錄著方法的名稱,方法實現以及引數型別
4.方法名稱,通過這個方法名稱就可以在方法列表中找到對應的方法實現
5.當我們傳送一個訊息給一個NSObject 物件時,這條訊息會在物件的類方法列表中查詢
6.當我們傳送一個訊息給一個類時,這條訊息會在類的 Meta Class 物件的方法列表中查詢
4.使用runtime Associate 方法關聯的物件,需要在主物件dealloc 的時候釋放嗎?
無論在MRC下還是ARC下均不需要被關聯的物件在生命週期內要比物件本身釋放的晚很多,他們會在被 NSObject-dealloc 呼叫的 object_dispose()方法中釋放
補充:物件的記憶體銷燬時間表,分為四個步驟
1、呼叫 -release: 引用計數變為零
* 物件正在被銷燬,生命週期即將結束。
* 不能再有新的 _weak 若飲用,否則將指向nil.
* 呼叫 [self dealloc]
2、父類呼叫-dealloc
* 繼承關係中最直接繼承的父類在呼叫 -dealloc
* 如果是 MRC 程式碼,則會手動釋放例項變數們(Ivars)
* 繼承關係中每一層的父類,都在呼叫 -dealloc
3、NSObject 呼叫 -dealloc
* 只做一件事:呼叫Objective-C runtime 中的object_dispose() 方法
4、呼叫objetc_dispose()
* 為 C++ 的例項變數們(Ivars)呼叫destructors
* 為 ARC 狀態下的例項變數們(Ivars)呼叫 -release
* 解除所有使用 runtime Associate 方法關聯的物件
* 呼叫所有 _weak 飲用
* 呼叫 free()
5. _objc_msgForward 函式是做什麼的?直接呼叫它將會發生什麼?
_objc_msgForward 是 IMP 型別,用於訊息轉發:當向一個物件傳送一條訊息,他並沒有實現的時候,_objc_msgForward 會嘗試做訊息轉發
直接呼叫 _objc_msgForward 會非常危險的事情,這是一把雙刃劍,用得好,會做很多非常酷的事情,但是用不好,會直接導致程式Creash.
6.能否向編譯後得到的類中增加例項變數?能否向執行時建立的類中增加例項變數?為什麼?
不能想編譯後的得到的類中增加例項變數;
能向執行時建立的類中新增例項變數;
原因如下:
1.因為編譯後的類已經註冊在runtime 中,類結構體中的 objc_ivar_list 例項變數的連結串列和instance_size 例項變數的記憶體大小已經確定,同時 runtime 會呼叫class_setIvarLayout 或 class_setWeakIvarLayout 來處理 strong weak 引用,所以不能向存在的類中新增例項變數
2.執行時建立的類是可以新增例項變數,呼叫class_addIcar 函式,但是得在呼叫 objc_allocateClassPair之後,objc_registerClassPair之後
7.簡述OC 中呼叫方法的過程(runtime)
OC 是動態語言,每個方法在執行時都會被動態轉為訊息傳送,即: objc_msgSend(seceiver,selector),整體過程如下:
1.objc. 在給一個物件傳送訊息時,runtime 庫會根據物件的 isa 指標找到該物件實際所屬的類
2.然後在該類中的方法列表一機其父類方法列表中尋找方法執行
3.如果,在最頂層的額父類(一般也就是NSObject )中依然找不到對應的方法時,程式在執行時會掛掉並丟擲異常 unrecongnized selector send to XXX
但是在這之前,objc 的執行時會給出三次機會拯救程式崩潰的機會
補充說明:Runtime 鑄就了OC 的動態語言的特性,使得C語言具備了面向物件的特性,在程式執行期間建立,檢查,修改類、物件以及其對應的方法,這些操作都可以使用 runtime 中的對應方法實現。
8.什麼是method swizzing?
* 簡單的說就是進行方法交換
* 在OC中呼叫一個方法,其實就是給一個物件傳送訊息,查詢訊息唯一一句就是selector 名字。利用OC 的動態特性,可以實現在執行時偷換 selector 對應的方法實現,達到給方法掛鉤的目的
* 每個類都有一個方法列表,存放著方法的名字和方法實現的對映關係,selector 的本質就是方法名, IMP 有點類似函式指標,指向具體的 Method 實現,通過 selector 找到對應的 IMP。
* 方法交換的幾種方式
<1>. 利用 method_exchangeImplementations 交換兩個方法的實現
<2>. 利用 class_replaceMethod 替換方法的實現
<3>.利用 method_setImplementation 來設定某個方法的 IMP