1.為什么不能給類(lèi)別category 添加成員變量?extension呢?
2.isKindOfClass: 和 -isMemberOfClas區(qū)別?
3.weak的實(shí)現(xiàn)原理
4.理解 [self class] 與 [super class] ?
5.ios中的內(nèi)存管理機(jī)制
6.Block如何訪問(wèn)外部變量? 下劃線__block的作用? 如何防止循環(huán)引用?
7.Block循環(huán)引用問(wèn)題
(1).為什么Msonry不會(huì)循環(huán)引用?
(2).weakSelf、strongSelf結(jié)合使用
8.深拷貝與淺拷貝
9.KVO實(shí)現(xiàn)原理
10.Runtime的原理及實(shí)際使用場(chǎng)景
講解
1.為什么不能給類(lèi)別category 添加成員變量?extension呢?
分類(lèi)并不會(huì)改變?cè)蓄?lèi)的內(nèi)存分布的情況,它是在運(yùn)行期間決定的,此時(shí)內(nèi)存的分布已經(jīng)確定,若此時(shí)再添加實(shí)例會(huì)改變內(nèi)存的分布情況,這對(duì)編譯性語(yǔ)言是災(zāi)難,是不允許的。
category 是基于運(yùn)行時(shí)的:
typedef struct category_t {
const char *name; //類(lèi)的名字
classref_t cls; //類(lèi)
struct method_list_t *instanceMethods; //category中所有給類(lèi)添加的實(shí)例方法的列表
struct method_list_t *classMethods; //category中所有添加的類(lèi)方法的列表
struct protocol_list_t *protocols; //category實(shí)現(xiàn)的所有協(xié)議的列表
struct property_list_t *instanceProperties; //category中添加的所有屬性
} category_t;
結(jié)構(gòu)體中并沒(méi)有成員變量這個(gè)list,所以無(wú)法在category添加成員變量,添加屬性是可以的,但是不會(huì)生成添加屬性的getter和setter方法,所以,盡管添加了屬性,也無(wú)法使用點(diǎn)語(yǔ)法調(diào)用getter和setter方法,但你可以使用運(yùn)行時(shí)實(shí)現(xiàn)關(guān)聯(lián)對(duì)象并可以引用。
反觀擴(kuò)展(extension),作用是為一個(gè)已知的類(lèi)添加一些私有的信息,必須有這個(gè)類(lèi)的源碼,才能擴(kuò)展,它是在編譯器生效的,所以能直接為類(lèi)添加屬性或者實(shí)例變量。
category跟extension最大的區(qū)別在于生效時(shí)間不一樣,category在運(yùn)行時(shí)生效,而extension在編譯時(shí)生效
2.isKindOfClass: 和 -isMemberOfClas區(qū)別?
isKindOfClass來(lái)確定一個(gè)對(duì)象是否是一個(gè)類(lèi)的成員,或者是派生自該類(lèi)的成員。一個(gè)實(shí)例對(duì)象的類(lèi)對(duì)象或類(lèi)對(duì)象的元類(lèi)是否與當(dāng)前類(lèi)相等,或派生自當(dāng)前類(lèi))
isMemberOfClass只能確定一個(gè)對(duì)象是否是當(dāng)前類(lèi)的成員。(一個(gè)實(shí)例對(duì)象的類(lèi)對(duì)象或類(lèi)對(duì)象的元類(lèi)是否與當(dāng)前類(lèi)相等)
詳解 :
類(lèi)方法+ (BOOL)isKindOfClass:(Class)cls,
元類(lèi) --> 根元類(lèi) --> 根類(lèi) --> nil 與 傳入類(lèi)的對(duì)比
這里會(huì)先取類(lèi)對(duì)象的isa (self->ISA()),類(lèi)對(duì)象的isa指向的是元類(lèi),判斷元類(lèi)是否與cls相等,而且這里是一個(gè)for循環(huán),不相等的話會(huì)往元類(lèi)的父類(lèi)(tcls = tcls->superclass)循環(huán)去查找對(duì)比。
實(shí)例方法- (BOOL)isKindOfClass:(Class)cls,
對(duì)象的類(lèi) --> 父類(lèi) --> 根類(lèi) --> nil 與 傳入類(lèi)的對(duì)比
這里是先取實(shí)例對(duì)象的isa ([self class]),也就是類(lèi)對(duì)象,判斷類(lèi)對(duì)象與cls是否相等,不相等的話會(huì)往類(lèi)對(duì)象的父類(lèi)(tcls = tcls->superclass)循環(huán)去查找對(duì)比。
類(lèi)方法+ (BOOL)isMemberOfClass:(Class)cls,
類(lèi)的元類(lèi) 與 傳入類(lèi) 對(duì)比
判斷的是類(lèi)對(duì)象的isa(即元類(lèi))是否等于cls。
實(shí)例方法- (BOOL)isMemberOfClass:(Class)cls,
對(duì)象的父類(lèi) 與 傳入類(lèi) 對(duì)比
判斷的是實(shí)例對(duì)象調(diào)用class方法的返回值(也就是類(lèi)對(duì)象)是否與cls相等。
iOS 捋清楚 isKindOfClass 與 isMemberOfClass
iOS 底層原理探索之 isKindOfClass & isMemberOfClass
3.weak的實(shí)現(xiàn)原理
weak是Runtime維護(hù)了一個(gè)hash(哈希)表,用于存儲(chǔ)指向某個(gè)對(duì)象的所有weak指針。weak表其實(shí)是一個(gè)hash(哈希)表,Key是所指對(duì)象的地址,Value是weak指針的地址(這個(gè)地址的值是所指對(duì)象指針的地址)數(shù)組。
對(duì)象準(zhǔn)備釋放時(shí),調(diào)用clearDeallocating函數(shù)。clearDeallocating函數(shù)首先根據(jù)對(duì)象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個(gè)entry從weak表中刪除,最后清理對(duì)象的記錄。
A.x = B;
__weak B.y = A;
當(dāng)A釋放時(shí),會(huì)根據(jù)A的地址獲取所有弱引用它的指針的地址(如B.y),把它置為nil。
4.理解 [self class] 與 [super class] ?
我們知道實(shí)際上在iOS中,對(duì)方法的調(diào)用是通過(guò)發(fā)送消息來(lái)完成的。也就是說(shuō)使用 [self class] 時(shí),會(huì)使用obj_msgSend(id theReceiver, SEL selector, ...)函數(shù)向Receiver來(lái)發(fā)送消息。而使用 [super class] 時(shí),會(huì)使用obj_msgsendSuper(...)函數(shù)向Receiver來(lái)發(fā)送消息。
————————————————
@implementation Son : Father
- (id)init
{
self = [super init];
if (self) {
NSLog(@”%@”, NSStringFromClass([self class]));
NSLog(@”%@”, NSStringFromClass([super class]));
}
return self;
}
@end
上邊代碼會(huì)輸出什么,為什么
簡(jiǎn)單來(lái)說(shuō),self和super都是指向當(dāng)前實(shí)例的,不同的是,[self class]會(huì)在當(dāng)前類(lèi)的方法列表中去找class這個(gè)方法,[super class]會(huì)直接開(kāi)始在當(dāng)前類(lèi)的父類(lèi)中去找calss這個(gè)方法,兩者在找不到的時(shí)候,都會(huì)繼續(xù)向祖先類(lèi)查詢(xún)class方法,最終到NSObject類(lèi)。那么問(wèn)題來(lái)了,由于我們?cè)贔ather和Son中都沒(méi)有去重寫(xiě)class這個(gè)方法,最終自然都會(huì)去執(zhí)行NSObject中的class方法,結(jié)果也自然應(yīng)該是一樣的。
至于為什么是Son,我們可以看看NSObject中class的實(shí)現(xiàn):
-(Class)class {
return object_getClass(self);
}
5.ios中的內(nèi)存管理機(jī)制
為了管理所有對(duì)象的引用計(jì)數(shù)和weak指針,蘋(píng)果創(chuàng)建了一個(gè)全局的SideTables,雖然名字后面有個(gè)"s"不過(guò)他其實(shí)是一個(gè)全局的Hash表,里面的內(nèi)容裝的都是SideTable結(jié)構(gòu)體而已。它使用對(duì)象的內(nèi)存地址當(dāng)它的key。管理引用計(jì)數(shù)和weak指針就靠它了。

6.Block如何訪問(wèn)外部變量? 下劃線__block修飾auto變量的作用? 如何防止循環(huán)引用?
auto變量含義:離開(kāi)作用域(大括號(hào)),會(huì)自動(dòng)釋放的變量
block在訪問(wèn)auto變量(局部變量)時(shí),block內(nèi)部會(huì)捕獲到外部變量的值,后面修改外部auto變量的值,block內(nèi)部的值不會(huì)隨著改變而改變
block在訪問(wèn)static變量(局部變量)時(shí),block內(nèi)部會(huì)捕獲到外部變量的地址值,所以后面修改外部static變量值的時(shí)候,通過(guò)地址訪問(wèn)到的是最新修改后的值。
當(dāng)auto變量加了__block修飾,編譯器會(huì)將__block變量包裝成一個(gè)對(duì)象,會(huì)捕獲到block內(nèi)部,并進(jìn)行指針傳遞,所以能夠修改其值(類(lèi)似于訪問(wèn)static變量)。
另外,靜態(tài)變量、全局變量和全局靜態(tài)變量,傳入的就是地址值,可以直接被block修改
- 為了避免循環(huán)引用,最好的是對(duì)block內(nèi)部引用的self對(duì)象進(jìn)行弱引用。一般使用一個(gè)弱指針來(lái)指向該對(duì)象,然后在block內(nèi)使用該弱引用指針來(lái)進(jìn)行操作,這樣就避免了block對(duì)該對(duì)象的強(qiáng)引用。
7.Block循環(huán)引用問(wèn)題
(1).為什么Msonry不會(huì)循環(huán)引用?
查看masonry源碼可以看到究竟:msonry中設(shè)置布局的方法中的block對(duì)象并沒(méi)有被View所引用,而是直接在方法內(nèi)部同步執(zhí)行,執(zhí)行完以后block將釋放,其中捕捉的外部變量的引用計(jì)數(shù)也將還原到之前。
(2).weakSelf、strongSelf結(jié)合使用
使用weakSelf結(jié)合strongSelf的情況下,能夠避免循環(huán)引用,也不會(huì)造成提前釋放導(dǎo)致block內(nèi)部代碼無(wú)效(野指針問(wèn)題)。
_person1 = [[Person alloc] init];
_person2 = [[Person alloc] init];
_person2.name = @"張三";
__weak __typeof(self) weakSelf = self;
_person1.block = ^{
__typeof(&*weakSelf) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",strongSelf.person2.name);
});
};
8.深拷貝與淺拷貝
淺拷貝就是拷貝之后,并沒(méi)有真正的復(fù)制,而是復(fù)制對(duì)象和原對(duì)象都指向同一個(gè)地址
深拷貝是真正的復(fù)制了一份,復(fù)制的對(duì)象只想新的地址
- copy:對(duì)于可變對(duì)象為深拷貝,對(duì)于不可變對(duì)象為淺拷貝
- mutablecopy:始終為深拷貝
注:
oc中只有遵循<NSCopying>才支持copy,只有遵循<NSMutableCopying>才支持mutablecopy,如果沒(méi)有遵循,拷貝時(shí)會(huì)直接crash。
這兩篇文章我覺(jué)得總結(jié)的不錯(cuò)
深刻理解iOS中的“深拷貝”和“淺拷貝”
iOS中NSString的strong、copy的使用
9.KVO實(shí)現(xiàn)原理
當(dāng)某個(gè)類(lèi)的對(duì)象屬性第一次被觀察時(shí),系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)地創(chuàng)建該類(lèi)的一個(gè)派生類(lèi),在這個(gè)派生類(lèi)中重寫(xiě)基類(lèi)中任何被觀察屬性的setter方法。派生類(lèi)在被重寫(xiě)的setter方法內(nèi)實(shí)現(xiàn)真正的通知機(jī)制。
當(dāng)觀察對(duì)象A時(shí),KVO機(jī)制動(dòng)態(tài)創(chuàng)建一個(gè)新的名為NSKVONotifying_A的新類(lèi),該類(lèi)集成字對(duì)象A的本類(lèi),且KVO為NSKVONotifying_A重寫(xiě)觀察屬性的setter方法,setter方法會(huì)負(fù)責(zé)在調(diào)用元setter方法之前和之后,通知所有觀察對(duì)象屬性值的更改情況。
被觀察屬性發(fā)生改變之前,willChangeValueForkey:被調(diào)用,通知系統(tǒng)該keyPath的屬性值即將變更;當(dāng)改變發(fā)生后,didChangeValueForkey:被調(diào)用,通知系統(tǒng)該keyPath的屬性值已經(jīng)變更;之后,observeValueForKey:ofObject:context:也會(huì)被調(diào)用。且重寫(xiě)觀察屬性的setter方法這種繼承方式的注入是在運(yùn)行時(shí)而不是編譯時(shí)實(shí)現(xiàn)的。
10.Runtime的原理及實(shí)際使用場(chǎng)景
主動(dòng)使用
1.字典轉(zhuǎn)模型
2.給分類(lèi)屬性添加get,set方法
3.方法交換swizzling
4.設(shè)置UITextField占位文字的顏色
···
隱式調(diào)用
1.KVO與KVC的實(shí)現(xiàn)。
2.內(nèi)存管理,weak表的維護(hù)。
···