本篇博客作為讀書筆記,主要記錄和整理閱讀EOC(《Effective Objective-C 2.0 編寫高質量iOS與OS X代碼的52個有效方法》)時的收貨和感悟
1.了解OC語言的起源
了解OC的語言特性(運行時),OC的發展來源(C的超集),語法,內存管理策略等。
2.在類的頭文件中盡量少引入其他頭文件
在.h中引入其他頭文件,會大幅度增加編譯所需的時間,也有可能會導致循環引入的問題。應當盡量使用“前向聲明”(@class)的方式來聲明其他類的存在。 為了避免在.h中引入定義協議的頭文件,遵守協議應該寫在.m中的類擴展里,而不是寫在.h中
3.多用字面量語法,少用與之等價的方法
了解和掌握用于快速創建NSNumber、NSArray、NSDictionary的字面量語法:@num,@[],@{};以及相應的下標運算符。需要了解數組和字典創建時遇到nil值會結束的特性,以及使用字面量語法帶來的好處。
4.多用類型常量,少用#define預處理指令
在定義僅類內部使用的常量時,應該盡量使用static const的方式來定義。這種定義的會限制其類型,并且避免其他文件的修改。當定義全局變量時,應使用在類內部定義全局變量,在頭文件中使用extern引用全局常量的做法。
5.用枚舉表示狀態、選項、狀態碼
了解為什么用枚舉更好、怎么使用C++11帶來的新枚舉用法,以及OC中定義的快速創建枚舉宏的用法。了解和掌握NS_ENUM和NS_OPTIONS宏的用法。
6.理解“屬性”這一概念
使用@property語法時,編譯器會自動生成getter方法和setter方法以及成員變量的。掌握@property的關鍵字:四種類型(原子性、內存管理策略、讀寫性、讀寫方法重命名),以及分別的使用場景和原理。
7.在對象內部盡量直接訪問實例變量
了解通過屬性訪問實例變量會觸發什么(調用setter或getter方法,觸發KVO)了解使用屬性來訪問成員變量和直接訪問成員變量兩者的區別與優劣:直接訪問成員變量效率更快。
8.理解“對象等同性”這一概念
了解isEqual:
這一方法的原理,了解NSString中isEqualToString:
這一方法做了什么事情。了解如果需要自定義方法來判斷兩個對象是否相等應該怎么做。
9.以“類族模式”隱藏實現細節
了解類族的概念,了解如何通過工廠方法來創建類族子類對象。掌握如何通過工廠模式設計工廠方法來實例化子類對象。
10.在既有類中使用關聯對象存放自定義數據
掌握runtime中的objc_setAssociatedObject
和objc_getAssociatedObject
方法的作用和用法。掌握冬天獲取和添加成員變量的方式。
11.理解objc_msgSend的作用
理解和掌握OC中的消息機制,理解"selector"、"IMP"的含義。了解objc_msgSend
方法的意義
12.理解消息轉發機制
了解OC運行時機制,了解當消息接收者無法處理消息時,會調用哪些方法。掌握使用resolveInstanceMethod:
或resolveClassMethod:
方法來動態添加方法、使用forwardingTargetForSelector:
方法來轉發消息、使用forwardInvocation:
方法來處理完整的消息轉發。
13.用“方法調配技術”調試“黑盒方法”
了解和掌握runtime方法調用流程,了解"method swizzling"的原理和用法,掌握使用class_getInstanceMethod
或class_getClassMethod
函數來獲取方法實現,使用method_exchangeImplementations
函數來交換方法實現。同時需要了解在使用"method swizzling"時,自定義的方法中如何規避調用自身的問題。
14.理解“類對象”的用意
了解OC對象的實現方式,了解“類對象”,“isa指針”,“元類對象”的概念。掌握isMemberOfClass:
方法和isKindOfClass:
方法的作用。
15.用前綴避免命名空間沖突
理解編寫自己的類時,使用命名前綴。
16.提供“全能初始化方法”
理解和掌握在類的初始化方法中提供一個被其他所有初始化方法調用的“全能初始化方法”。其他初始化方法都調用這個方法來創建實例對象,在這個初始化方法中進行對象的具體配置。
17.實現description方法
掌握通過重寫自定義類的description方法來實現描述信息的返回。了解使用debugDescription方法在LLDB中進行調試打印。
18.盡量使用不可變對象
理解定義公開屬性時盡量使用不可變版本的原因,了解在類擴展中修改為readwrite以便類內部可以修改。了解對外公開的集合屬性的返回方式。
19.使用清晰而協調的命名方式
了解OC中方法名的命名規范,了解駝峰法書寫方式,方法名在言簡意賅的同時最好能完整敘述方法的功能,并給每個參數都加上相應的提示。 方法名中不要使用類型名的縮寫而是使用類型名的全稱。類名、協議名要加上對應的前綴。
20.為私有方法名加前綴
為了避免與公有方法混亂,或是無意中覆蓋了父類中的共有方法,在書寫類的私有方法時應該給方法加上前綴,比如以p_
為前綴。不要僅使用一個單下劃線_
作為私有方法的前綴,避免和系統類的私有方法重合。
21.理解Objective-C錯誤模型
了解NSException的使用方法和應用場景。了解NSError的使用。
22.理解NSCopying協議
在OC中想要拷貝一個對象時,通常使用copy方法。該對象對應的類需要遵循NSCopying
協議,并實現協議中的copyWithZone:
方法。如果需要拷貝可變的版本,則需要遵守NSMutableCopying
協議并實現mutableCopyWithZone:
方法。了解深拷貝和淺拷貝的區別以及實現方式。
23.通過委托與數據源協議進行對象間通信
理解OC中代理設計模式的實現思路,掌握delegate和dataSource形式的協議設計。性能優化方面,可以將代理是否實現了代理方法在賦值時進行緩存,可以大大優化頻繁調用代理方法時的效率。
24.將類的實現代碼分散到便于管理的數個分類中
可以將不同模塊的代碼分散到類的分類中,僅把主要的核心代碼保存在主文件中。分類既可以存放在主文件的中,劃分不同模塊保存,也可以創建不同的分類文件進行保存。
25.總是為第三方類的分類名稱加前綴
為了避免重名的情況,分類文件名都應該盡量加上前綴。為了避免分類中的方法實現覆蓋了其他分類中的實現或原實現,應該給方法名也加上相應的前綴。
26.勿在分類中聲明屬性
由于分類中不會合成屬性對應的成員變量,因此不應該在分類中聲明屬性。雖然可以使用runtime動態添加的方式綁定,但這一并不好,不應該在非必須的時候這樣做。分類中應該盡量只用來擴充方法。
27.使用“class-continuation分類”隱藏實現細節
掌握使用類擴展來給類擴充私有實例變量。如果想要使主接口中聲明為“只讀”的屬性能夠在內部修改,應該在類擴展中將其改寫為“可讀寫”
28.通過協議提供匿名對象
了解通過協議來隱藏對象類型細節。如果具體類型不重要,重要的是對象能響應的方法,可以使用匿名對象的方式實現。
29.理解引用計數
了解和掌握OC中進行內存管理的機制,了解引用計數的概念,以及在MRC環境下進行對象內存管理所需使用到的常用方法(retain,release,autorelease,delloc)。
30.以ARC簡化引用計數
了解ARC的概念,明白編譯器在ARC環境下做了哪些事情。并且理解循環引用的概念,了解怎么在ARC模式下怎么避免內存泄漏。
31.在delloc方法中只釋放引用并解除監聽
在delloc方法中只應該進行釋放對象引用(尤其是CF中的對象),以及移除觀察者、通知監聽的操作。如果有大量占用內存的對象需要提前釋放,應該在自定義的方法中釋放。
32.編寫“異常安全代碼”時留意內存管理問題
由于在ARC環境下,捕獲異常時沒辦法釋放對象引用,所以需要開啟編譯器的-fobjc-arc-exceptions標志來避免內存泄露。不過在非必要的時候不要開啟,避免對性能的影響。
33.以弱引用避免保留環
當有循環引用時,使用weak指針(__weak修飾符)來修飾對象,避免循環引用導致的內存泄漏。
34.以“自動釋放池塊”降低內存峰值
在MRC環境下,可以通過手動創建自動釋放池的方式來提前釋放內存。
35.用“僵尸對象”調試內存管理問題
通過在編譯器scheme中編輯中打開僵尸對象的監測來解決懸垂指針的問題。了解僵尸對象的概念和行成過程。
36.不要使用retainCount
即使在MRC模式下,retainCount方法返回的引用計數也并不可靠,不要使用該方法進行對象內存管理的判斷。
37.理解“塊”這一概念
了解block的基本概念和使用場景,了解自定義block類型的方式。了解block對象的內存管理情形。
38.為常用的塊類型創建typedef
掌握使用typedef給block起別名,把類中常用的block類型定義為自定義的數據類型。
39.用handler塊降低代碼分散程度
掌握使用block回調的方式進行傳值,使用completionHandler來處理完成回調,或者以兩個block參數分別作為成功和失敗的回調。這樣做比使用delegate的方式更加便捷,并且具有可讀性。
40.用塊引用其所屬對象時不要出現保留環
由于block會自動捕獲其中使用到的對象,對其進行一次引用,所以在使用block時需要注意循環引用的情況。可以通過手動解除引用的方式解決,也可以通過將被捕獲的對象用__weak修飾符修飾的方式解決。
41.多用派發隊列,少用同步鎖
當需要自己編寫帶有線程安全機制的代碼時,可以考慮使用GCD的同步異步函數方式來實現。
42.多用GCD,少用performSelector系列方法
performSelector方法由于存在內存管理的缺陷,以及參數和返回值類型限制等問題,不建議使用。最好使用GCD的方法來實現方法調用和線程通信。
43.掌握GCD及操作隊列的使用時機
了解和掌握NSOperation的使用,在實現多線程時也可以考慮使用。當需要處理任務取消、添加依賴、鍵值觀察、指定任務優先級這些gcd無法實現的功能時應該用NSOperation來解決。
44.通過Dispatch Group機制,根據系統資源狀況來執行任務
當需要等待某個或某些任務執行完畢時,可以通過將任務添加到一個隊列組的方式實現。使用dispatch_group_notify方法來實現當隊列中任務全部完成時執行某一代碼塊。
45.使用dispatch_once來執行只需運行一次的線程安全代碼
當需要編寫在整個程序運行的生命周期中只會運行一次的代碼,可以使用gcd的dispatch_once函數來實現。單例設計模式中推薦使用這種方式而不是線程鎖
46.不要使用dispatch_get_current_queue
dispatch_get_current_queue函數已經廢棄,而且該函數返回的隊列很可能與開發者預期的不同,因此使用的時候容易出現問題。應使用隊列特定數據的方式來解決。
47.熟悉系統框架
熟練掌握Foundation框架和CoreFoundation框架的主要功能,熟悉常用的音頻視頻處理、網絡通信、數據管理等系統框架,避免在開發中自己去實現一些系統已經實現好了的功能。
48.多用塊枚舉,少用for循環
掌握幾種遍歷集合的方式,掌握使用塊循環enumerateObjectsUsingBlock:
方法來實現遍歷。
49.對自定義其內存管理語義的collection使用無縫橋接
了解和掌握Foundation對象和CoreFoundation數據結構之間轉換的方式。
50.構建緩存時選用NSCache而非NSDictionary
在進行數據持久化緩存時,應該優先使用NSCache類來實現。NSCache相比NSDictionary具有自動刪減、線程安全、不拷貝鍵的優勢。
51.精簡initialize與load的實現代碼
load方法在代碼被加載到代碼區的時候調用,盡量不要在load方法中做復雜的工作,避免影響應用程序的啟動速度。load方法和initialize方法中都應該避免對其他類的調用,避免加載或初始化時機差異導致的問題。未實現load方法的子類,即使父類實現了,也不會調用;未實現initialize方法的子類,會調用其父類的方法。
52.別忘了NSTimer會保留其目標對象
當創建一個Timer對象時,timer會保留其引用到的target對象,如果timer的模式是重復執行的,那么會有很大的可能產生循環引用。應該使用block的方式創建,或手動invalidate timer來避免內存泄露的問題.