前一段時間和一同事聊天,聊到一個話題,關于學習曲線的的話題,雖說有很多不一致,但有一點我們一致認同的深度決定高度!為此,我再次看了這本書(Objective-C 高級編程)。
該書從以下三部分出發,自動引用計數、Blocks、Grand Central Dispatch,在源代碼的基礎上加以解說,深入剖析。 非常建議購買看原版書籍!非常值得???/strong>,因為第一遍可能看不懂,哈哈哈。
在此,我以筆記的形式,邊學習,邊記錄,便于自己堅持。
自動引用計數
什么是自動引用計數
定義:自動引用計數是指內存管理中對引用采取的自動計數的技術。
注意點:在 LLVM 編譯器中設置 ARC 為有效狀態,就無需再次輸入 retain 或者是 release 代碼。
好處:這在降低程序奔潰,內存泄露等風險的同時,很大程度上減少了開發程序的工作量。
內存管理 / 引用計數
2.1 引用計數的機制理解
以經典的開燈例子舉例,在辦公室內至少有一人保持開燈狀態,無人時保持關燈狀態
最早進入辦公室的人 ===> 開燈 ==== > 生成對象
之后進入辦公室的人 ===> 需要照明 ==== > 持有對象
下班離開辦公室的人 ===> 不需要照明 ==== > 釋放對象
最后下班離開辦公室的人===> 關燈 ==== > 廢棄對象
中間無論多少人,只要遵循進來就需要照明,走就不要照明。這樣辦公室的照明就可以得到很好的管理;同理使用引用計數功能,對象也能夠得到很好的管理。
注意:release方法
當引用計數等于零時會自動使用dealloc方法
。
原則:
- 自己生成的對象,自己持有。
- 非自己生成的對象,自己也能持有。
- 不再需要自己持有的對象時釋放。
- 非自己持有的對象無法釋放。
** 2.2、alloc,retain,release的實現的理解 **
由于 NSObject 的源碼沒有公開,此利用 Xcode 的調試器和 iOS 大概追溯其實現過程。
- alloc
+alloc
+allocWithZone:
Class_createInstance
calloc
alloc類方法首先調用 allocWithZone:類方法,然后調用 class_instance 函數,最后通過 calloc 來分配內存塊。這樣就相當于 alloc 的實現啦。
- retain、release
int __CFDoExternRefOpreation(uintptr_t op, id obj) {
CFBasicHashRef table = 獲取對應的是散列表obj(); // 獲取對應的是散列表
int count;
switch (op) {
case OPREATION_retainCount:
count = CFBasicHashGetCountOfKey(table, obj);
return count;
case OPREATION_retain:
count = CFBasicHashAddVlaue(table, obj);
return count;
case OPREATION_release:
count = CFBasicHashRemoveValue(table, obj);
// count == 0的時候,調用 dealloc
return 0 == count;
}
}
然后真正的對象實現的方法也許如下:
- (NSUInteger)reatainCount
{
return (NSUInteger) __CFDoExternRefOpreation(OPREATION_retainCount, self);
}
- (id)retain
{
return (id) __CFDoExternRefOpreation(OPREATION_retain, self);
}
- (void)release
{
return __CFDoExternRefOpreation(OPREATION_release, self);
}
蘋果的實現大概是采用 散列表(引用計數表)來管理引用計數器。
這樣做的好處:
對象用內存筷發分配無需考慮內存塊的頭部。
引用計數表各記錄都有內存塊地址,可從各個記錄追訴哦到各對象的的內存塊。
同時檢測內存泄露時,很方便檢測各對象的持有者是否存在
以上大致是 retain 、release 的理解,NSObject 在實例化該方法的時候先去調用一個類似 CFDoExternRefOpreation的函數,然后實現相應的方法 CFBasicHashRemoveValue 或 CFBasicHashAddVlaue,通過CFBasicHashRef table (引用計數表)整體的管理它的引用計數,來實現 retain 或 release。這就是大致的實現過程啦。