![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
第五章 內存管理
第29條、理解引用計數
29.一、引用計數的工做原理
在引用計數框架下,對象有個計數器,用以表示當前有多少個事物想令此對象繼續存活下去。這在OC中叫作 「保留記數」,也叫 「引用計數」。編程
引用計數機制經過能夠遞增遞減的計數器來管理內存。對象建立好以後,其保留計數至少爲1。若保留計數爲正,則對象繼續存活。當保留計數降爲0時,對象就被銷燬了。數組
NSObject 協議聲明瞭下面三個方法用於操做計數器:緩存
- retain 遞增保留計數
- release 遞減保留計數
- autorelease 自動釋放
爲避免在不經意間使用了無效對象,通常調用完 release 以後都會清空指針。這樣能保證不會出現可能指向無效對象的指針,這種指針一般被稱爲 「懸掛指針」。安全
29.二、屬性存取方法中的內存管理
- (void)setFoo:(id)foo {
[foo retain];
[_foo release];
_foo = foo;
}複製代碼
29.三、自動釋放池
在 OC 的引用計數架構中。調用 release 會馬上遞減對象的保留計數,這裏可該用 autorelease,此方法會在稍後遞減計數,一般在洗下一次 「事件循環」 時遞減,不過也可能提早執行。網絡
autorelease 能延長對象生命期,使其在跨越方法調用邊界後依然能夠存活一段時間。數據結構
第30條、以 ARC 簡化引用計數
能夠經過編譯器的 「靜態分析器」 來指明程序裏引用計數出問題的地方。能夠根據須要,預先加入適當的保留或釋放操做以免內存管理的問題。
閉包
因爲 ARC 會自動執行 retain、release、autorelease等操做,因此直接在ARC下調用這些內存管理方式是非法的。架構
ARC 在調用這些方法時,並不經過消息派發機制,而是直接調用其底層C語言版本,這樣作性能更好,由於保留及釋放操做須要頻繁操做,因此直接調用底層函數能節省不少CPU週期。好比:ARC會調用與 retain 等價的底層函數 objc_retain。框架
30.一、使用ARC時必須遵循的方法命名規則
將內存管理語義在方法名中表示出來早已成爲OC的慣例,而 ARC 則將之確立爲硬性規定。這些規則簡單滴體如今方法名上。若方法名如下列詞語開頭,則其返回的對象歸調用者全部:異步
- alloc
- new
- copy
- mutableCopy
ARC 經過命命約定將內存管理規則標準化,除了會自動調用 「保留」 與 「釋放」 方法外,使用ARC 還有其餘好處,他能夠執行一些手工操做很難甚至沒法完成的優化。
如:ARC 會把可以互相抵消的 retain、release、autorelease 操做約簡。若是發如今同一個對象上執行了屢次 「保留」 與 「釋放」 操做,那麼 ARC 有時能夠成對地移除這兩個操做。
30.二、變量的內存管理語義
注意與屬性的內存管理語義區分
可用下列修飾符來改變局部變量與實例變量的語義:
- __strong:默認語義,保留此值;
- __unsafe_unretained:不保留此值,這麼作可能不安全,由於等到再次使用變量時,其對象可能已經回收了;
- __weak:不保留此值,可是變量能夠安全使用,由於若是系統把這個對象回收了,那麼變量也會自動清空;
- __autoreleasing:把對象 「按引用傳遞」 給方法時,使用這個特殊的修飾符。此值在方法返回時自動釋放。
第31條、在 dealloc 方法中只釋放引用並解除監聽
- 在 dealloc 方法裏,應該作的事情就是釋放指向其餘對象的引用,並取消原來訂閱的 KVO 或 NSNotifaicationCenter等通知,不要作其餘事情;
- 若是對象持有文件描述等系統資源,那麼應該專門編寫一個方法來釋放此種資源。這樣的類要和其使用者約定:用完資源後必須調用 close 方法;
- 執行異步任務的方法不該在 dealloc 裏調用,只能在正常狀態下執行的那些方法也不該在 dealloc 裏調用,由於此時對象已經處於正在回收的狀態了;
- 在 dealloc 裏也不要調用屬性的存取方法。
第32條、編寫 「異常安全代碼」 時留意內存管理問題
- 捕獲異常時,必定要注意將 try 塊內所創立的對象清理乾淨;
- 在默認狀況下,ARC 不生成安全處理異常所需的清理代碼。開啓編譯器標誌後,可生成這種代碼,不過會致使應用程序變大,並且會下降運行效率。
第33條、以弱引用避免保留環
- 將某些引用設爲 weak,可避免出現 「保留環」;
- weak 引用能夠自動清空,也能夠不自動清空。自動清空是隨着 ARC 而引入的新特性,由運行期系統來實現。在具有自動清空功能的弱引用上,能夠隨意讀取其數據,由於這種引用不會指向已經回收過的對象。
第34條、以 「自動釋放池塊」 下降內存峯值
- 自動釋放池排布在棧中,對象收到 autorelease 消息後,系統將其放入最頂端的池裏;
- 合理運用自動釋放池,可下降應用程序的內存峯值;
- @autoreleasepool 這種新式寫法能建立出更爲輕便的自動釋放池。
第35條、用 「殭屍對象」 調試內存管理問題
第36條、不要使用 retainCount
NSObject 協議中定義 - (NSUInteger)retainCount
用於查詢對象當前的保留計數。然而 ARC 已經將此方法廢棄了。
此方法之因此無用,其首要緣由在於:任何給定時間點上的 「絕對保留計數」 都沒法反映對象生命期的全貌。
第6章 Block 與 GCD
第37條、理解 「塊」 這一律念
- 塊是C、C++、Objective-C 中的詞法閉包;
- 塊可接受參數,也可返回值;
- 塊能夠分配在棧或堆上,也能夠是全局的。
第38條、爲經常使用的塊類型建立 typedef
- 以 typedef 從新定義塊類型,可令塊變量用起來更加簡單;
- 定義新類型時應聽從現有的命名習慣,勿使其名稱與別的類型相沖突;
- 不妨爲同一個塊簽名定義多個類型別名。
第39條、用 handler 塊下降代碼分散程度
- 在建立對象時,可使用內聯的 handler 塊將相關業務邏輯一併聲明;
- 在有多個實例須要監控時,若是採用委託模式,那麼常常須要根據傳入的對象來切換,而若該用 handler 塊來實現,則可直接將塊與相關對象放在一塊兒;
- 設計 API 時若是用到了 handler 塊,那麼能夠增長一個參數,使調用者可經過此參數來決定應該把塊安排在哪一個隊列上執行
第40條、用塊引用其所屬對象時不要出現保留環
- 若是塊所捕獲的對象直接或間接地保留了塊自己,那麼得小心保留環問題;
- 必定要找個適當的時機解除保留環,而不能把責任推給 API 的調用者。
第41條、多用派發隊列,少用同步鎖
- 派發隊列可用來表述同步語義,這種作法要比使用 @synchronized 塊或 NSLock 對此昂更簡單;
- 將同步與異步派發結合起來,能夠實現與普通加鎖機制同樣的同步行爲,而這麼作卻不會阻塞執行異步派發的線程;
- 使用同步隊列及柵欄塊,能夠令同步行爲更加高效。
第42條、多用 GCD,少用 performSelector 系列方法
第43條、掌握 GCD 及操做隊列的使用時機
第44條、經過 Dispatch Group 機制,根據系統資源情況來執行任務
第45條、使用 dispatch_once 來執行只需運行一次的線程安全代碼
第46條、不要使用 dispatch_get_current_queue
第7章 系統框架
第47條、熟悉系統框架
將一系列代碼封裝爲動態庫,並在其中放入描述其接口的頭文件,這樣作出來的東西就叫框架。
Foundation 框架中的類,使用 NS 這個前綴,此前綴是在 OC語言 做爲 NeXTSTEP 操做系統的編程語言時首度肯定的。
CoreFoundation,與 Foundation 框架相伴。Foundation 框架中的許多功能,均可以在此框架中找到對應的C語言 API。
AppKit 及 UIKit,構建在 Foundation 與 CoreFoundation 之上的 OC類。
- 許多系統框架均可以直接使用。其中最重要的是 Foundation 與 CoreFoundation,這兩個框架提供了構建應用程序所需的許多核心功能;
- 不少常見任務都能用框架來作,例如音頻與視頻處理、網絡通訊、數據管理等;
- 用純C寫成的框架與用OC寫成的同樣重要,若想成爲優秀的OC開發者,應該掌握C語言的核心概念
第48條、多用塊枚舉,少用for循環
- 遍歷集合有四種方式。最基本的辦法就是 for 循環、其次是 NSEnumerator 遍歷法、快速遍歷法和 「塊枚舉法」;
- 「塊枚舉法」 自己就能經過 GCD 來並法執行遍歷操做,無需另行編寫代碼。而採用其餘遍歷方法則沒法輕易實現這一點;
- 若提早知道待遍歷的 collection 含有何種對象,則應修改塊簽名,指出對象的具體類型。
第49條、對自定義其內存管理語義的 collection 使用無縫橋接
OC 的系統庫包含至關多的 collection 類,其中有各類數組、各類字典、各類set。
Foundation 框架定義了這些 collection 及其餘各類 collection 所對應的 OC 類。
CoreFoundation 框架也定義了一套 C語言API,用於操做表示這些 collection 及其餘各類 collection 的數據結構。
例如:
NSArray 是 Foundation 框架中表示數組的 OC 類。
CFArray 是 CoreFoundation 框架中的等價物。
這兩種建立數組的方式也許有區別,然而有項強大的功能可在這兩個類型之間平滑轉換,他就是 「無縫橋接」。
第50條、構建緩存時選用 NSCache 而非 NSDictionary
NSCache 是 Foundation 框架專門處理緩存任務而設計的
- 實現緩存時應選 NSCache 而非 NSDictionary 對象。由於 NSCache 能夠提供優雅的自動刪減功能,並且是 「線程安全的」,此外,它與字典不一樣,並不會拷貝鍵;
第51條、精簡 initialize 與 load 的實現代碼
- 在加載階段,若是類實現了 load 方法,那麼系統就會調用它。分類裏也能夠定義此方法,類的 load 方法要比分類中的先調用。與其餘方法不一樣,load 方法不參與覆寫機制;
- 首次使用某個類以前,系統會向其發送 initialize 消息。因爲此方法聽從普通的覆寫規則,因此一般應該在裏面判斷當前要初始化的是哪一個類;
- load 與 initialize 方法都應該實現得精簡一些,這有助於保持應用程序的響應能力,也能減小引入 「依賴環」 的概率;
- 沒法在編譯器設定的全局常量,能夠放在 initialze 方法裏初始化。
第52條、別忘了 NStimer 會保留其目標對象
- NSTimer 對象會保留其目標,直到計時器自己失效ei zhi