這篇文章你將看到以下內容:
- Efficetive Objective-C 2.0閱讀筆記一些有價值的建議
1.對象內部盡量直接訪問實例變量
直接訪問實例變量為直接訪問內存,效率比調用屬性高。
- 訪問實例變量不會觸發KVO
-
-init
及-dealloc
方法中應使用實例變量 - 對象內部應盡量遵守如下原則:取值采用實例變量,賦值采用屬性。
2.消息轉發機制流程
3.盡量使用不可變對象
- 集合中盡量添加不可變對象,否則可能會發生與集合本身語義有分歧的后果,eg:
NSMutableArray * arr1 = @[@1].mutableCopy;
NSMutableArray * arr2 = @[@1,@2].mutableCopy;
NSSet * set = [NSSet setWithObjects:arr1,arr2, nil];
[arr1 addObject:@2];//至此set中居然包含了兩個相同的元素
NSSet * setCopy = [set copy];//書中此處表述setCopy應只有一個元素,然實測有兩個相同元素
- 對象對外公開集合類盡量使用不可變集合
- 對象對外公開
readOnly
屬性,內部可以通過重新聲明為readWrite
來使用屬性值。如此操作后和能會由于競態使得部分情況外部可以修改屬性值,外部也可通過KVC來更改屬性值
4.將類的實現代碼分散到便于管理的數個分類之中
通過分類機制,可以把類代碼分成很多個易于管理的小塊,以便單獨檢視。
之所以要將類代碼打散到分類中還有個原因,就是便于調試:對于某個分類中的所有方法來說,分類名稱都會出現在其符號中。
將應該視為“私有”的方法歸入名叫Private的分類中,以隱藏實現細節。
5.在-dealloc中只釋放引用并解除監聽
- 在
-dealloc
方法里,應該做的事情就是釋放指向其他對象的引用,并取消原來訂閱的“鍵值觀測”(KVO)或NSNotificationCenter等通知,不要做其他事情。 - 如果對象持有文件描述符等系統資源,那么應該專門編寫一個方法來釋放此種資源。這樣的類要和其他使用者約定:用完資源后必須調用close方法。
- 執行異步任務的方法不應再
-dealloc
里調用;只能子啊正常狀態下執行的那些方法也不應在-dealloc
里調用,因為此時對象已處于正在回收的狀態了。
6.以自動釋放池降低內存峰值
比方說,在循環中不斷地創建的臨時對象。即便這些對象在調用完方法之后就就不在使用了,他們也依然處于存活狀態,因為目前還在自動釋放池里,等待系統稍后將其釋放并回收。然而,自動釋放池要等線程執行下一次runLoop時才會清空。這樣依賴,執行for循環時,應用程序所占內存量就會持續上漲,而等到所有臨時對象都釋放后,內存用量又會突然下降。
然而在循環中合理的位置添加自動釋放池,應用程序在執行循環時的內存峰值就會降低。
7.多用派發隊列,少用同步鎖
濫用@synchronized(self)
會降低代碼效率,因為共用同一個鎖的那些同步塊,都必須按順序執行。若想實現同步機制,可以以并行隊列、同步任務及柵欄實現,代碼如下:
_syncQueue = dispatch_queue_create("com.syncQ.Wicky", DISPATCH_QUEUE_CONCURRENT);///創建并行隊列
///getter
-(NSString *)someString {
__block NSString * localString;
dispatch_sync(_syncQueue, ^{
localString = _someString;
});
return localString;
}
///setter
-(void)setSomeString:(NSString *)someString {
dispatch_barrier_async(_syncQueue, ^{
_someString = someString;
});
}
8.多用GCD,少用performSelector系列方法
由于在編譯器無法確定performSelector方法是否具有返回值,故編譯器沒有對對象進行引用計數管理,因此可能造成內存泄漏。
另外performSelector返回值只能是id類型的對象,基本數據類型可能需要開發人員進行進一步的類型轉換。
如果想要添加延時任務,條件允許的情況下應盡可能選擇GCD。
9.合理使用GCD與NSOperation
GCD為純C的API,而NSOperation則是OC對象。與NSOperation比起來GCD更加輕量,然而NSOperation卻有以下幾點在使用上更加便捷:
- 取消操作
- 指定依賴關系
- 提供KVO監聽
- 指定優先級
- 重用對象
10.多用Block枚舉,少用for循環
Block枚舉擁有其他遍歷方式具備的所有優勢,而且還能帶來更多好處。與快速遍歷法相比,他還要多用一些代碼,可是卻能提供遍歷時所針對的下標,在遍歷字典時也能同時提供鍵與值,而且還有選項可以開啟并發迭代功能,所以多寫這點代碼還是值得的。
11.精簡+initialize與+load的實現代碼
- 在加載階段,如果類實現了
+load
方法,那么系統就會先調用他。分類里也可以定義此方法,類的+load
方法要比分類中的先調用。與其他方法不同,+load
方法不參與覆寫機制。 - 首次使用某個類之前,系統會向其發送
+initialize
消息。由于此方法遵從普通的覆寫機制,所以通常應該在里面判斷當前要初始化的是哪個類。 -
+load
與+initialize
方法都應該實現的精簡一些,這有助于保持應用程序的響應能力,也能減少引入“依賴環”的幾率。 - 無法在編譯器設定的全局常量,可以放在
+initialize
方法里初始化。