1.你使用過Objective-C的運(yùn)行時(shí)編程么?如果使用過,你用它做了什么?你還能記得你所使用的相關(guān)的頭文件或者某些方法的名稱嗎?
NSObjCRuntime.h/NSObject.h/message.h/objc-api.h/objc-auto.h/objc-exception.h(異常操作)/objc-sync.h/objc.h(基本功能)/runtime.h(主要功能在runtime.h中)
2.runtime實(shí)現(xiàn)的機(jī)制是什么,怎么用,一般用于干嘛?
runtime是一套比較底層的純C語言API, 屬于1個(gè)C語言庫, 包含了很多底層的C語言API。平時(shí)編寫的OC代碼, 在程序運(yùn)行過程中, 其實(shí)最終都是轉(zhuǎn)成了runtime的C語言代碼, runtime算是OC的幕后工作者。
runtime是屬于OC的底層, 可以進(jìn)行一些非常底層的操作(用OC是無法現(xiàn)實(shí)的, 不好實(shí)現(xiàn))
- 在程序運(yùn)行過程中, 動態(tài)創(chuàng)建一個(gè)類(比如KVO的底層實(shí)現(xiàn))
- 在程序運(yùn)行過程中, 動態(tài)地為某個(gè)類添加屬性方法, 修改屬性值
遍歷一個(gè)類的所有成員變量(屬性)所有方法
3.kvo的實(shí)現(xiàn)原理是什么?
KVO是基于runtime機(jī)制實(shí)現(xiàn)的。
當(dāng)某個(gè)類的對象第一次被觀察時(shí),系統(tǒng)就會在運(yùn)行期動態(tài)地創(chuàng)建該類的一個(gè)派生類,在這個(gè)派生類中重寫基類中任何被觀察屬性的setter方法。
派生類在被重寫的setter方法實(shí)現(xiàn)真正的通知機(jī)制(Person->NSKVONOtifying Person)
Person類對象p設(shè)置self控制器且設(shè)置監(jiān)聽屬性,就會調(diào)用observeValueForKeyPath方法,當(dāng)Person類的屬性被改變時(shí),就會動態(tài)生成一個(gè)子類繼承自Person類(NSKVONotifying_Person),重寫setAge方法,內(nèi)部調(diào)用父類setAge方法,通知監(jiān)聽器
[監(jiān)聽器 observeValueForKeyPath:@"age" ofObject:self change:@{} context:(void *)context];
原先age屬性不改變時(shí)p對象 isa指向Person,當(dāng)age屬性改變時(shí)p對象 isa指向NSKVONotifying_Person(setAge重新內(nèi)部就會傳遞變量至父類且通知監(jiān)聽器age屬性改變)
4.objc_setAssociatedObject、objc_getAssociatedObject是什么,有什么優(yōu)點(diǎn)?
建立對象關(guān)聯(lián),使用關(guān)聯(lián),我們可以不用修改類的定義而為其對象增加存儲空間。這在我們無法訪問到類的源碼的時(shí)候或者是考慮到二進(jìn)制兼容性的時(shí)候是非常有用。
關(guān)聯(lián)是基于關(guān)鍵字的,因此,我們可以為任何對象增加任意多的關(guān)聯(lián),每個(gè)都使用不同的關(guān)鍵字即可。關(guān)聯(lián)是可以保證被關(guān)聯(lián)的對象在關(guān)聯(lián)對象的整個(gè)生命周期都是可用的(在垃圾自動回收環(huán)境下也不會導(dǎo)致資源不可回收)。
5.method swizzling是干什么的,一般用于哪里?
方法混用,可以通過runtime獲取類的方法表。一個(gè)方法Method由三個(gè)部分組成SEL方法選標(biāo)、IMP函數(shù)指針、typeEncode??梢灾苯觕lass_replaceMethod替換原有方法,method_exchangeImplementations效果兩個(gè)方法的實(shí)現(xiàn)或者method_setImplementation直接修改方法實(shí)現(xiàn)。
向視圖控制器的生命周期中注入操作、事件的響應(yīng)、視圖的繪制,或Foundation中的網(wǎng)絡(luò)堆棧都是能夠利用method swizzling產(chǎn)生明顯效果的場景。還有一些其他的場景使用swizzling會是一個(gè)合適的選擇,這隨著Objective-C開發(fā)者經(jīng)驗(yàn)不斷豐富會變得越來越明顯。
6.可以向nil對象發(fā)送消息么?如果向一個(gè)nil對象發(fā)送消息將會發(fā)生什么?
在Objective-C中向nil發(fā)送消息是完全有效的——只是在運(yùn)行時(shí)不會有任何作用。
7.category,method 的實(shí)現(xiàn)機(jī)制是什么?
根據(jù)蘋果官方文檔對 Category 的描述,它的使用場景主要有三個(gè):
給現(xiàn)有的類添加方法;
將一個(gè)類的實(shí)現(xiàn)拆分成多個(gè)獨(dú)立的源文件;無論我們有沒有主動引入 Category 的頭文件,Category 中的方法都會被添加進(jìn)主類中。將 Category 和它的主類(或元類)注冊到哈希表中;
如果主類(或元類)已實(shí)現(xiàn),那么重建它的方法列表。
在這里分了兩種情況進(jìn)行處理:Category 中的實(shí)例方法和屬性被整合到主類中;而類方法則被整合到元類中。將 Category 中的方法、屬性和協(xié)議整合到類(主類或元類)中,更新類的數(shù)據(jù)字段 data() 中 method_lists(或 method_list) 、 properties 和 protocols 的值。
8.runtime如何實(shí)現(xiàn)weak變量的自動置nil?
runtime 對注冊的類, 會進(jìn)行布局,對于 weak 對象會放入一個(gè) hash 表中。 用 weak 指向的對象內(nèi)存地址作為 key,當(dāng)此對象的引用計(jì)數(shù)為0的時(shí)候會 dealloc,假如 weak 指向的對象內(nèi)存地址是a,那么就會以a為鍵, 在這個(gè) weak 表中搜索,找到所有以a為鍵的 weak 對象,從而設(shè)置為 nil。
9.objc使用什么機(jī)制管理對象內(nèi)存?
通過 retainCount 的機(jī)制來決定對象是否需要釋放。 每次 runloop 的時(shí)候,都會檢查對象的 retainCount,如果retainCount 為 0,說明該對象沒有地方需要繼續(xù)使用了,可以釋放掉了。
10.為什么說Object-C是runtime language? runtime有什么優(yōu)點(diǎn)?
將數(shù)據(jù)類型的確定由編譯時(shí),推遲到了運(yùn)行時(shí)。運(yùn)行時(shí)機(jī)制使我們直到運(yùn)行時(shí)才去決定一個(gè)對象的類別,以及調(diào)用該類別對象指定方法。實(shí)現(xiàn)多態(tài),不同對象以自己的方式響應(yīng)相同的消息的能力。
11.什么是動態(tài),舉例說明
OC具有很多的動態(tài)特性,有動態(tài)類型(Dynamic typing),動態(tài)綁定(Dynamic binding)和動態(tài)加載(Dynamic loading).OC在底層也提供了相當(dāng)豐富的運(yùn)行時(shí)特性,比如枚舉類屬性方法,獲取方法實(shí)現(xiàn)等.
動態(tài)特性 :
動態(tài)類型:即運(yùn)行時(shí)再決定對象的類型.id類型即通用的對象類,任何的對象都可以用id類型來指向(通常用于不知道該對象為什么類型的對象的時(shí)候才使用).
id obj = name;
if ([obj isKindOfClass:[NSString class]]) {
NSString * str = (NSString *)name;
}
isKindOfClass:用于確定某個(gè)NSObject對象是否是某個(gè)類的成員. 而isMemberOfClass:是NSObject方法,用于確定某個(gè)對象是否是某個(gè)類或其子類的成員
動態(tài)綁定:經(jīng)過動態(tài)類型確定實(shí)例對象之后,該實(shí)例對象對應(yīng)的屬性和一些方法也隨即被確定,根據(jù)類的確定,確定了類的屬性和類的方法.OC中調(diào)用一個(gè)實(shí)例的方法,就是通過OC的消息機(jī)制發(fā)送一個(gè)消息,實(shí)例在收到消息后,從自身的實(shí)現(xiàn)中找到方法來響應(yīng).動態(tài)綁定就是實(shí)例所屬的類經(jīng)過運(yùn)行后確定,將類的屬性和方法綁定在動態(tài)類型上,而不是實(shí)現(xiàn)確定的,因?yàn)轭愐彩莿討B(tài)類型的
動態(tài)加載:所謂動態(tài)加載就是我們做開發(fā)的時(shí)候icon圖片的時(shí)候在Retina設(shè)備上要多添加一個(gè)張@2x的圖片,當(dāng)設(shè)備更換的時(shí)候,圖片也會自動的替換,還有就是我們公司主板項(xiàng)目中根據(jù)服務(wù)器返回的類名來動態(tài)創(chuàng)建類.
iOS開發(fā)的運(yùn)行時(shí)特性
我們做開發(fā)的時(shí)候會經(jīng)常用到Protocol-Delegate的設(shè)計(jì)模式,所以不管是我們使用的,還是我們自己定義的delegate指針類型必須是id類型的,只有這樣我們才能夠滿足程序運(yùn)行時(shí)delegate的來回切換.
12.runtime有啥用?
1>能動態(tài)產(chǎn)生一個(gè)類、一個(gè)成員變量、一個(gè)方法
2>能動態(tài)修改一個(gè)類、一個(gè)成員變量、一個(gè)方法
3>能動態(tài)刪除一個(gè)類、一個(gè)成員變量、一個(gè)方法
其常見的函數(shù)、頭文件
import <objc/runtime.h> : 成員變量、類、方法
class_copyIvarList : 獲得某個(gè)類內(nèi)部的所有成員變量
class_copyMethodList : 獲得某個(gè)類內(nèi)部的所有方法
class_getInstanceMethod : 獲得某個(gè)具體的實(shí)例方法(對象方法,減號開頭)
class_getClassMethod : 獲得某個(gè)具體的類方法 (加號)
method_exchangeImplementations : 交換2個(gè)方法的實(shí)現(xiàn)
import <objc/message.h> 消息機(jī)制
objc_msgSend(...);
runtime可以實(shí)現(xiàn)遍歷所有成員變量,使用runtime機(jī)制,某類交換2個(gè)方法的實(shí)現(xiàn)交換2個(gè)方法的好處:以后一個(gè)大項(xiàng)目當(dāng)中的一個(gè)方法使用過多,想動一些手腳和操作,就可以很方便實(shí)現(xiàn)。