面試系列:
-
iOS全解1:基礎(chǔ)/內(nèi)存管理/Block/GCD(
當前位置
) - iOS全解2:Runloop
- iOS全解3:Runtime
- iOS全解4:KVC/KVO热芹、通知/推送/信號量、Delegate/Protocol惨撇、Singleton
- iOS全解5:網(wǎng)絡協(xié)議 HTTP伊脓、Socket
- iOS全解6:CoreAnimation/Layer
- iOS全解7:音頻/視頻
- iOS全解8:啟動優(yōu)化、性能優(yōu)化魁衙、App后臺北ㄇ唬活、崩潰檢測
- iOS全解9:編程思想剖淀、架構(gòu)纯蛾、組件化、RAC
基本概念
一纵隔、OC的三大特性為:封裝
翻诉、繼承
、多態(tài)
1捌刮、封裝:
- 變量 的封裝:setter碰煌、getter 方法,self調(diào)用方便高效
- 方法 的封裝:簡潔绅作、高效芦圾,不用關(guān)心內(nèi)部過程
- SDK 的封裝:使用方便、私有隱藏棚蓄,安全性高(不會泄露數(shù)據(jù)和代碼)
2堕扶、繼承
- 抽取了重復代碼:子類可以擁有父類中的所有成員變量和方法
- 建立了類與類之間的聯(lián)系
- 每個類中都有一個superclass指針指向父類
- 所有類的根類都是NSObject,便于isa指針 查詢
- 調(diào)用某個對象的方法時梭依,優(yōu)先去當前類中找,如果找不到典尾,再去父類中找
- 子類重新實現(xiàn)父類的某個方法役拴,會覆蓋父類以前的方法。
繼承的缺點:耦合性太高(類與類之間的關(guān)系過于緊密)钾埂,沒有多繼承河闰,OC里面都是單繼承科平,多繼承可以用protocol委托代理來模擬實現(xiàn);可以通過實現(xiàn)多個接口完成OC的多重繼承姜性。(實現(xiàn)多個協(xié)議)
3瞪慧、多態(tài)
例如: -(void) animal:(id); id 就是多態(tài),傳入時部念,才識別 具體類的真實形象弃酌。runtime 也是運行時,才識別具體類儡炼。
要想使用多態(tài)必須使用繼承(繼承是多態(tài)的前提)
多態(tài):父類指針指向子類對象 Animal *aa = [Dog new]; 調(diào)用方法時會檢測對象的真實形象
好處:如果函數(shù)或方法參數(shù)中使用的是父類類型妓湘,可以傳入父類,子類對象乌询。
局限性:父類類型的變量不能直接調(diào)用子類特有的方法榜贴,必須強制轉(zhuǎn)換為子類類型變量后,才能使用妹田。
內(nèi)存管理RAC:
ARC 相對于 GC 的優(yōu)點:
ARC 工作在編譯期大年,在運行時沒有額外開銷彭谁。
ARC 的內(nèi)存回收是平穩(wěn)進行的,對象不被使用時會立即被回收。而 GC 的內(nèi)存回收是一陣一陣的凡恍,回收時需要暫停程序,會有一定的卡頓点额。
ARC 相對于 GC 的缺點:
GC 真的是太簡單了咪啡,基本上完全不用處理內(nèi)存管理問題,而 ARC 還是需要處理類似循環(huán)引用
這種內(nèi)存管理問題房铭。
property的關(guān)鍵字分三類:
1.原子性(也就線程安全)
有atomic和nonatomic, acomic就是線程安全驻龟,但是一般使用nonacomic,因為acomic的線程安全開銷太大,影響性能缸匪,即使需要保證線程安全翁狐,我們也可以通過自已的代碼控制,而不用acomic凌蔬。
2.引用計數(shù):
assign:
assign用于非指針變量露懒,基本修飾數(shù)據(jù)類型,統(tǒng)一由系統(tǒng)的棧區(qū)進行內(nèi)存管理砂心。(int懈词、double、float等)
weak:
對對象的弱引用辩诞,不增加引用計數(shù)坎弯,也不持有對象,當對象消失后指針自動變?yōu)閚il。
copy:分為深拷貝抠忘、淺拷貝撩炊,可變復制、不可變復制
淺拷貝
:對內(nèi)存地址的復制崎脉,讓目標對象指針和原對象指向同一片內(nèi)存空間會增加引用計數(shù)
深拷貝
:對對象內(nèi)容的復制拧咳,開辟新的內(nèi)存空間
單層深復制
,也就是我們經(jīng)常說的深復制囚灼,我這里說的單層深復制是對于集合類所說的(即NSArray骆膝、NSDictionary、NSSet)啦撮,單層深復制指的是只復制了該集合類的最外層谭网,里邊的元素沒有復制,(即這兩個集合類的地址不一樣赃春,但是兩個集合里所存儲的元素的地址是一樣的)
完全復制
愉择,指的是完全復制整個集合類,也就是說兩個集合地址不一樣织中,里邊所存儲的元素地址也不一樣
引用:深拷貝和淺拷貝锥涕,可變復制,不可變復制(這里解釋更詳細)http://www.reibang.com/p/e3da07684bf1
- 非集合類(NSString狭吼,NSNumber)
[noMutableObject copy] //淺復制 (復制不可變對象)
[noMutableObject mutableCopy] //深復制 (復制不可變對象)
[mutableObject copy] //深復制 (復制可變對象)
[mutableObject mutableCopy] //深復制 (復制可變對象)
- 集合類(NSArray层坠,NSDictionary, NSSet)
[noMutableObject copy] //淺復制 (復制不可變對象)
[noMutableObject mutableCopy] //單層深復制 (復制不可變對象)
[mutableObject copy] //單層深復制 (復制可變對象)
[mutableObject mutableCopy] //單層深復制 (復制可變對象)
- 那么如何實現(xiàn)多層復制呢?我們以NSArray舉例說明
// 完全復制
NSArray *copyArray = [[NSArray alloc] initWithArray:array copyItems:YES];
需要特別注意的是
以上我們所說的兩種情況默認都實現(xiàn)了NSCopying
和NSMutableCopying
協(xié)議刁笙。
對于自定義繼承自NSObject的類
copy需要實現(xiàn)NSCopying協(xié)議破花,然后實現(xiàn)以下方法,否則copy會crash
-(id)copyWithZone:(NSZone *)zone {
CopyObject *copy = [[[self class] alloc] init];
copy.name = self.name;
copy.mobile = self.mobile;
copy.company = self.company;
copy.descInfo = self.descInfo;
return copy;
}
mutableCopy時疲吸,需要實現(xiàn)NSMutableCopying協(xié)議座每,否則mutableCopy會crash
-(id)mutableCopyWithZone:(NSZone *)zone {
MutableCopyObject *mutableCopy = [[[self class] alloc] init];
mutableCopy.name = self.name;
mutableCopy.mobile = self.mobile;
mutableCopy.company = self.company;
mutableCopy.descInfo = self.descInfo;
return mutableCopy;
}
strong:淺拷貝,也就是指針引用
是每對這個屬性引用一次摘悴,retainCount 就會+1峭梳,只能修飾 NSObject 對象,不能修飾基本數(shù)據(jù)類型蹂喻。是 id 和 對象 的默認修飾符葱椭。
unsafe_unretained:和week 非常相似
可以同時修飾基本數(shù)據(jù)類型和 NSObject 對象 ,其實它本身是 week 的前身 , 在 iOS5 之后口四,基本都用 week 代替了 unsafe_unretained 孵运。 但它們之間還是稍微有點區(qū)別的,并不是完全一樣蔓彩,對上層代碼來說掐松,能用 unsafe_unretained 的地方踱侣,都可以用 week 代替粪小〈蠡牵“同時要注意一點,這個修飾符修飾的變量不屬于編譯器的內(nèi)存管理對象”
二探膊、類別Category
重寫一個類的方式用「繼承」還是「分類」杠愧,取決于具體情況:
- 假如目標類有許多的子類,我們需要拓展這個類又不希望影響到原有的代碼逞壁,繼承后比較好流济。
- 如果僅僅是拓展方法,分類更好.(不需要涉及到原先的代碼)
優(yōu)點:
- 分類中方法的優(yōu)先級比原來類中的方法高腌闯,也就是說绳瘟,在分類中重寫了原來類中的方法,那么分類中的方法會覆蓋原來類中的方法姿骏。+(void)load方法是一個特例糖声,它會在當前類執(zhí)行完之后,category中的再執(zhí)行分瘦。)
- 可以用runtime進行method swizzling(方法的偷梁換柱)來處理異常調(diào)用的方法蘸泻。
缺點:
通過觀察頭文件我們可以發(fā)現(xiàn),Cocoa框架中的許多類都是通過category來實現(xiàn)功能的嘲玫,可能不經(jīng)意間你就覆蓋了這些方法中的其一悦施,有時候就會產(chǎn)生一些無法排查的異常原因。
其他問題
淺拷貝和深拷貝的區(qū)別去团?
淺拷貝
:只復制指向?qū)ο蟮闹羔樎盏羔樦赶蛲粋€地址,而不復制引用對象本身土陪。
深拷貝
:復制引用對象本身昼汗。內(nèi)存中存在了兩份獨立對象本身,當修改A 時旺坠,B 不變乔遮。(即:B = [A copy]; )
一、內(nèi)存管理
案例:
辦公室開關(guān)燈
取刃,有人開燈蹋肮,無人關(guān)燈;進人加一璧疗,出人減一坯辩;第一個開燈的人持有此燈,第一個人能廢棄此燈崩侠,其他人只是弱引用漆魔。
內(nèi)存管理原則:
1.自己生成的對象,自己持有
2.非自己生成的對象,自己也能持有
3.不再需要自己持有的對象時改抡,釋放掉
4.非自己持有的對象矢炼,無法釋放(釋放會崩潰)
對象操作與Objective-C方法的對應
對象操作 | Objective-C方法 |
---|---|
生成并持有對象 | alloc、new阿纤、copy句灌、mutableCopy |
持有對象 | retain (引用計數(shù)加1) |
釋放對象 | release(引用計數(shù)減1) |
廢棄對象 | dealloc(引用計數(shù)為0) |
相關(guān)釋放函數(shù):autorelease、NSAutoreleasePool欠拾、@autoreleasepool
2胰锌、非自己生成的對象,自己也能持有
id obj = [NSMutableArray array];
[obj retain];
* 使用autorelease方法藐窄,可以取得對象的存在资昧,但是自己不持有對象(obj不立刻釋放掉,注冊到autoreleasePool中)
- (id)object {
id obj = [[NSObject alloc] init];
[obj autorelease];
return obj;
}
ARC 環(huán)境下的使用功能規(guī)則
- 不能使用retain荆忍、release格带、retainCount、autorelease
- 不能使用NSAllocateObject东揣、NSDeallocateObject
- 必須遵循內(nèi)存管理命名規(guī)則(駝峰命名法)
- 不要顯式調(diào)用dealloc
- 使用 @autorelease 代替 NSAutoreleasePool
- 不能使用區(qū)域 (NSZone)
- 對象型變量不能作為C語言結(jié)構(gòu)體(struct/union)的成員
- 顯式轉(zhuǎn)換 “id” 和 “void *”
會讓對象引用計數(shù)增加的操作:
1. new践惑、alloc、retain嘶卧、copy尔觉、mutableCopy
2. 添加視圖:用 addview 把一個控件添加到視圖上,這個控件的引用計數(shù)+1芥吟;
3. 添加數(shù)組:把一個對象添加到數(shù)組中侦铜,數(shù)組內(nèi)部會把這個對象的引用計數(shù)+1;
4. 屬性賦值:會讓對象的引用計數(shù)+1钟鸵;
5. 屬性關(guān)聯(lián):xib中的控件钉稍,跟代碼關(guān)聯(lián)后,會讓對象的引用計數(shù)+1棺耍;
6. push這個操作會讓對象的引用計數(shù)增加贡未。
ARC、MRC混編
- ARC環(huán)境下 使用MRC代碼蒙袍,使用 -fno-objc-arc轉(zhuǎn)換
- MRC環(huán)境下 使用ARC代碼俊卤,使用 -fobjc-arc轉(zhuǎn)換
所有權(quán)修飾符
- _ _strong 修飾符
- _ _weak 修飾符
- _ _unsafe_unretained 修飾符(MRC環(huán)境下使用)
- _ _autoreleasing 修飾符 (ARC環(huán)境下使用)
1、_ _strong修飾符是id類型和對象類型的默認修飾符害幅,一般是隱式的消恍;
id obj = [[NSObject alloc] init];
//同上
id _ _strong obj = [[NSObject alloc] init];
2、 _ _weak 解決 循環(huán)引用的 修飾符以现,防止內(nèi)存泄漏狠怨。在持有某對象的弱引用時约啊,若該對象被廢棄,則弱引用自動失效佣赖,且被賦值nil恰矩,不在持有該對象(持有的對象超出作用域,會被廢棄銷毀)茵汰。
3枢里、_ _unsafe_unretained 和 _ _weak修飾的變量一樣,因為自己生成并持有的對象不能繼續(xù)為自己所有蹂午,所以生成的對象會被立即釋放。
4彬碱、_ _autoreleasing 隱式修飾符:非自己生成的對象豆胸,自己也能持有,會注冊到自動釋放池中巷疼。
屬性聲明的屬性 與 所有權(quán)修飾符的對應關(guān)系
聲明的屬性 | 所有權(quán)修飾符 | 說明 |
---|---|---|
assign | _ _unsafe_unretained | 修飾基本數(shù)據(jù)類型晚胡,如NSInteger和CGFloat,這些數(shù)值主要存在于棧上嚼沿。 |
copy | _ _strong | 每次復制會在內(nèi)存中拷貝一份對象估盘,指針指向不同的地址 |
retain | _ _strong | 用來持有對象 |
strong | _ _strong | 持有對象,引用計數(shù)會增加1骡尽。該對象只要引用計數(shù)不為0則不會被銷毀遣妥。當然強行將其設為nil可以銷毀它。 |
unsafe_unretained | _ _unsafe_unretained | 不安全持有 |
weak | _ _weak | 不擁有該對象攀细。其修飾的對象引用計數(shù)不會增加箫踩。無需手動設置,該對象會自行在內(nèi)存中銷毀谭贪。 |
釋放對象時境钟,廢棄對象不被持有的動作:
1、objc_release (釋放)
2俭识、因為引用計數(shù)為0慨削,所以執(zhí)行dealloc(釋放內(nèi)存)
3、_objc_rootDealloc(根解除)
4套媚、object_dispose(廢棄處理)
5缚态、objc_destructInstance(銷毀)
6、objc_clear_deallocating(清除)
對象被廢棄時凑阶,最后調(diào)用objc_clear_deallocating的動作(相關(guān)表 SideTables
):
1猿规、從weak表中獲取廢棄對象的記錄(地址為鍵值)。address= h(key)
2宙橱、將包含在記錄中的所有附有_ _weak修飾符變量的地址姨俩,賦值nil蘸拔。
3、從weak表中刪除該記錄环葵。
4调窍、從引用計數(shù)表中刪除廢棄對象的記錄(地址為鍵值)。
/* MRC環(huán)境
* NSAutoreleasePool
* autorelease
*/
- (void)test2 {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];
//同上
@autoreleasepool {
id obj = [[NSObject alloc] init];
[obj autorelease];
}
//同上 (ARC:ReferenceCountingVC2 )
@autoreleasepool {
id __autoreleaseing obj2;
obj2 = obj
}
}
下面了解幾個概念:
內(nèi)存泄漏:
應當廢棄的對象在超出其生存周期后繼續(xù)存在张遭。
野指針:
指針變量未初始化邓萨,其值是隨機的;指針釋放后未置空菊卷,指向不存在的內(nèi)存缔恳。
懸垂指針:
指向曾經(jīng)存在的對象,但是該對象已經(jīng)不存在了洁闰。
標記指針:
Tagged Pointer
是一種特殊的“指針”歉甚,其特殊在于,其實它存儲的并不是地址扑眉,而是真實的數(shù)據(jù)和一些附加的信息纸泄。(后面做專門講解)
isa 指針:
NONPOINTER_ISA
對象的isa指針,用來表明對象所屬的類類型和一些附加信息腰素。(nonPointer_isa 后面做專門講解)
標記指針: Tagged Pointer
tagged pointer是一種特殊的“指針”聘裁,其特殊在于,其實它存儲的并不是地址弓千,而是真實的數(shù)據(jù)和一些附加的信息衡便。
可以看到,利用tagged pointer后计呈,“指針”即存儲了對象本身砰诵,也存儲了和對象相關(guān)的標記。這時的tagged pointer里面存儲的不是地址捌显,而是一個數(shù)據(jù)集合茁彭。同時,其占用的內(nèi)存空間也由16字節(jié)縮減為8字節(jié)扶歪。
(即:Tagged Pointer = 對象本身 + 對象相關(guān)標記)
我們可以在WWDC2013的《Session 404 Advanced in Objective-C》視頻中理肺,看到蘋果對于Tagged Pointer特點的介紹:
? Tagged Pointer專門用來存儲小的對象,例如NSNumber
,NSDate
,NSString
善镰。
? Tagged Pointer指針的值不再是地址了妹萨,而是真正的值。實際上它不再是一個對象了炫欺,它只是一個披著對象皮的普通變量而已乎完。所以,它的內(nèi)存并不存儲在堆中品洛,也不需要malloc和free树姨。
? 在內(nèi)存讀取上有著3倍的效率摩桶,創(chuàng)建時比以前快10倍
例如:NSString
其輸出的class類型為 NSTaggedPointerString
。在字符串長度在9個以內(nèi)時帽揪,iOS其實使用了tagged pointer做了優(yōu)化的硝清。
直到字符串長度大于9,字符串才真正成為了__NSCFString
類型转晰。
首先芦拿,iOS需要一個標志位來判斷當前指針是真正的指針還是tagged pointer。
在runtime源碼的objc-internal.h中查邢,有關(guān)于標志位
的定義如下:
#if __has_feature(objc_fixed_enum) || __cplusplus >= 201103L
enum objc_tag_index_t : uint16_t
#else
typedef uint16_t objc_tag_index_t;
enum
#endif
{
OBJC_TAG_NSAtom = 0,
OBJC_TAG_1 = 1,
OBJC_TAG_NSString = 2, // 標志位是2的 tagger pointer表示這是一個NSString對象蔗崎。
OBJC_TAG_NSNumber = 3,
OBJC_TAG_NSIndexPath = 4,
OBJC_TAG_NSManagedObjectID = 5,
OBJC_TAG_NSDate = 6,
OBJC_TAG_RESERVED_7 = 7,
OBJC_TAG_First60BitPayload = 0,
OBJC_TAG_Last60BitPayload = 6,
OBJC_TAG_First52BitPayload = 8,
OBJC_TAG_Last52BitPayload = 263,
OBJC_TAG_RESERVED_264 = 264
};
#if __has_feature(objc_fixed_enum) && !defined(__cplusplus)
typedef enum objc_tag_index_t objc_tag_index_t;
#endif
‘地址’以
0xa
開頭,轉(zhuǎn)換為二進制是1010
, 首位1表示這是一個tagged pointer
侠坎,而010轉(zhuǎn)換為十進制是2蚁趁,表示這是一個NSString類型
。‘地址’以
0xb
開頭实胸, 轉(zhuǎn)換為二進制是1011
, 首位1表示這是一個tagged pointer
, 而011轉(zhuǎn)換為十進制是3,表示這是一個NSNumber類型
番官。
(即:標志位是2的tagger pointer表示這是一個NSString對象庐完。)
由于一個tagged pointer所指向的并不是一個真正的OC對象,它其實是沒有isa屬性的徘熔。
isa 指針(NONPOINTER_ISA)
isa:
是一個指向?qū)ο笏鶎貱lass類型的指針门躯。(nonPointer_isa)
對象的isa指針,用來表明對象所屬的類類型和一些附加信息酷师。
如果isa指針僅表示類型的話讶凉,對內(nèi)存顯然也是一個極大的浪費。于是山孔,就像tagged pointer一樣懂讯,對于isa指針,蘋果同樣進行了優(yōu)化
台颠。isa指針表示的內(nèi)容變得更為豐富褐望,除了表明對象屬于哪個類之外,還附加了 「引用計數(shù)」extra_rc
串前,是否有被weak引用標志位weakly_referenced
瘫里,是否有附加對象標志位has_assoc
等信息。(rc:reference counter 引用計數(shù))
//------- NSObject(實質(zhì)) -------
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
//------- objc_class(繼承)-------
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable 以前的緩存指針和虛函數(shù)表
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags class_rw_t *加上自定義rr/alloc標志
//荡碾。谨读。。
}
//------- isa指針(指向)-------
struct objc_object {
private:
isa_t isa;
public:
Class ISA(); // ISA() assumes this is NOT a tagged pointer object 假設這不是一個標記的指針對象
Class getIsa(); // getIsa() allows this to be a tagged pointer object 允許這是一個標記的指針對象
//坛吁。劳殖。铐尚。
}
//------- 聯(lián)合體(定義)-------
union isa_t
{
isa_t() { } //構(gòu)造函數(shù)1
isa_t(uintptr_t value) : bits(value) { } //構(gòu)造函數(shù)2
Class cls; //成員1(占據(jù)64位內(nèi)存空間)
uintptr_t bits; //成員2(占據(jù)64位內(nèi)存空間)
#if SUPPORT_PACKED_ISA
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
struct { //成員3(占據(jù)64位內(nèi)存空間:從低位到高位依次是nonpointer到extra_rc。成員后面的:表明了該成員占用幾個bit闷尿。)
uintptr_t nonpointer : 1; //(低位)注意:標志位塑径,表明isa_t *是否是一個真正的指針!L罹摺统舀!
uintptr_t has_assoc : 1; // 關(guān)聯(lián)對象
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1; //弱引用
uintptr_t deallocating : 1;
uintptr_t has_sidetable_rc : 1; //引用計數(shù) 相關(guān)成員1
uintptr_t extra_rc : 19; //引用計數(shù) 相關(guān)成員2 (用19位來 記錄對象的引用次數(shù))
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
};
}
引用于書籍《Objective-C高級編程》
GNUstep 是Cocoa 框架的互換框架。
CF:Core Foundation
CFRutime.c
蘋果的實現(xiàn)大概是采用散列表(引用計數(shù)表)來管理引用計數(shù)劳景。
在runtime中誉简,有四個數(shù)據(jù)結(jié)構(gòu)非常重要,分別是SideTables
盟广、SideTable
闷串、weak_table_t
和weak_entry_t
。它們和對象的引用計數(shù)筋量,以及weak引用相關(guān)烹吵。
(相關(guān)記錄,我的電腦文件:101-Runtime基礎(chǔ))
引用計數(shù)表的關(guān)系
其實在絕大多數(shù)情況下桨武,僅用優(yōu)化的isa_t
來記錄對象的引用計數(shù)
就足夠了肋拔。只有在19位的extra_rc
盛放不了那么大的引用計數(shù)時,才會借助SideTable出馬呀酸。
SideTable:是一個 全局的引用計數(shù)表凉蜂,它記錄了所有對象的引用計數(shù)。
先說一下這四個數(shù)據(jù)結(jié)構(gòu)的關(guān)系性誉。 在runtime內(nèi)存空間中窿吩,SideTables 是一個長度為8個元素 的hash數(shù)組,里面存儲了SideTable
错览。SideTables
的hash鍵值就是一個對象obj的address纫雁。即:table1 = h(address1)
因此可以說,一個obj蝗砾,對應了一個SideTable
先较。但是一個SideTable
,會對應多個obj悼粮。因為SideTable
的數(shù)量只有64個闲勺,所以會有很多obj共用同一個SideTable
。
SideTables
SideTable地址 | 關(guān)鍵字 |
---|---|
table1 = h ( address1 ) | address1 |
table2 = h ( address2 ) | address1 |
table3 = h ( address3 ) | address1 |
... | ... |
SideTable
obj對象地址 | 關(guān)鍵字 |
---|---|
address1 = h ( key1 ) 扣猫、RefcountMap1菜循、weak_table1 | key1 |
address2 = h ( key2 ) 、RefcountMap2申尤、weak_table2 | key2 |
address3 = h ( key3 )癌幕、RefcountMap3衙耕、weak_table3 | key3 |
... | ... |
而在一個SideTable中,又有3個成員勺远,分別是:
spinlock_t slock
: 自旋鎖橙喘,用于上鎖/解鎖 SideTable。RefcountMap refcnts
:以DisguisedPtr<objc_object>為key的hash表胶逢,用來存儲OC對象的引用計數(shù)(僅在未開啟isa優(yōu)化 或 在isa優(yōu)化情況下isa_t的引用計數(shù)溢出時才會用到)厅瞎。weak_table_t weak_table
: 存儲對象弱引用指針的hash表。是OC weak功能實現(xiàn)的核心數(shù)據(jù)結(jié)構(gòu)初坠。
struct
weak_table_t
{
weak_entry_t *weak_entries
; // 保存了所有指向指定對象的 weak 指針
size_tnum_entries
; // 存儲空間
uintptr_tmask
; // 參與判斷引用計數(shù)輔助量
uintptr_tmax_hash_displacement
; // hash key 最大偏移值
};
其中和簸,refcents
是一個hash map,其key是obj的地址碟刺,而value锁保,則是obj對象的引用計數(shù)。 即:referenceCount = h ( address )
而weak_table
則存儲了弱引用obj的指針的地址半沽,其本質(zhì)是一個以obj地址為key爽柒,弱引用obj的指針的地址作為value的hash表。hash表的節(jié)點類型是weak_entry_t
者填。 即:objPointer = h ( address )
二霉赡、Block
三、GCD與多線程
iOS全解1-3:鎖幔托、GCD與多線程
iOS全解1-4:NSURLSession
參考文章,如有問題請聯(lián)系本人QQ1178690076
Object-C高級編程讀書筆記(1)——Block的基本概念
Object-C高級編程讀書筆記(2)——Block的實質(zhì)
Object-C高級編程讀書筆記(3)——Block的變量截取
Object-C高級編程讀書筆記(4)——__block說明符
Object-C高級編程讀書筆記(5)——Block的對象類型截取
Objective-C runtime機制(1)——基本數(shù)據(jù)結(jié)構(gòu):objc_object & objc_class
Objective-C runtime機制(2)——消息機制
Objective-C runtime機制(3)——method swizzling
Objective-C runtime機制(4)——深入理解Category
Objective-C runtime機制(5)——iOS 內(nèi)存管理
Objective-C runtime機制(6)——weak引用的底層實現(xiàn)原理
Objective-C runtime機制(7)——SideTables, SideTable, weak_table, weak_entry_t
Objective-C runtime機制(8)——OC對象從創(chuàng)建到銷毀
Objective-C runtime機制(9)——main函數(shù)前發(fā)生了什么
Objective-C runtime機制(10)——KVO的實現(xiàn)機制
Objective-C runtime機制(11)——結(jié)業(yè)考試