編寫高質量iOS與OS X代碼的52個有效方法 - 學習筆記 五、六、7


第五章 內存管理

第29條、理解引用計數

29.一、引用計數的工做原理

在引用計數框架下,對象有個計數器,用以表示當前有多少個事物想令此對象繼續存活下去。這在OC中叫作 「保留記數」,也叫 「引用計數」。編程

引用計數機制經過能夠遞增遞減的計數器來管理內存。對象建立好以後,其保留計數至少爲1。若保留計數爲正,則對象繼續存活。當保留計數降爲0時,對象就被銷燬了。數組

NSObject 協議聲明瞭下面三個方法用於操做計數器:緩存

  • retain 遞增保留計數
  • release 遞減保留計數
  • autorelease 自動釋放

爲避免在不經意間使用了無效對象,通常調用完 release 以後都會清空指針。這樣能保證不會出現可能指向無效對象的指針,這種指針一般被稱爲 「懸掛指針」。安全

29.二、屬性存取方法中的內存管理

//訪問屬性時,會用到相關實例變量的獲取方法及設置方法。
//若屬性爲「strong關係」,則設置的屬性值會被保留。
- (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
相關文章
相關標籤/搜索