目錄
接口與API設計
用前綴避免命名空間沖突
提供“全能初始化方法”
實現description方法
盡量使用不可變對象
使用清晰而協調的命名方式
方法命名
?編輯類與協議命名
為私有方法名加前綴
理解OC錯誤模型
理解NSCopying協議
協議與分類
通過委托與數據源協議進行對象間通信
將類的實現代碼分散到便于管理的數個分類之中
總是為第三方類的分類名稱加前綴
?使用"class-continuation分類"隱藏實現細節
通過協議提供匿名對象
接口與API設計
用前綴避免命名空間沖突
為了避免“重名符號錯誤”,應當為所有名稱都加上適當前綴,可以與公司、程序或二者皆有關。
但使用Cocoa創建程序時,要注意Apple保留使用所有“兩字母前綴”的權利,所以開發者使用的前綴應該是三個字母的。
不僅是類,還有C函數的名字也應加上前綴
如果是開發第三方庫,那么對于所有包含的第三方庫代碼都加上自己的前綴。
提供“全能初始化方法”
可以為對象提供必要信息以便其能完成工作的初始化方法叫做“全能初始化方法”。
在上圖方法中,initWithTimeIntervalSinceReferenceDate:便是全能初始化方法。
當一個類有多個初始化方法時,仍要選定一個作為全能初始化方法,其他初始化方法都調用它。
只有在全能初始化方法中,才會存儲內部數據,這樣的話,當底層數據存儲機制改變時,只需修改此方法的代碼就好。
如果子類的全能初始化方法與超類方法的名稱不同,那么總應覆寫超類的全能初始化方法。
實現description方法
在自定義類中,description的默認實現是打印類名和地址,輸出信息如下:
這時我們應盡量將輸出信息改為一個有意義的字符串,用來描述這個實例。有個簡單的方法,就是借助NSDictionary的description方法。此方法輸出的信息的格式如下:
字符串可以采用如下格式:
若想在調試時打印更詳盡的描述信息,應實現debugDescripption方法。
盡量使用不可變對象
在編程實踐中,應該盡量把對外公布出來的屬性設為只讀,而只在確有必要時才將屬性對外公布。
有時可能想修改封裝在對象內部的數據,但是不想讓這些數據為外人所改動,這種情況下通常做法是將readonly重新聲明為readwrite,這一操作應該在"class-continuation分類"中完成。
在定義類的公共API時,還應注意:對象里表示各種collection的那些屬性應該設成可變的,還是不可變的。
比如:我們用某個類來表示個人信息,該類中還存放了一些引用指向此人的朋友,開發者可以添加或刪除朋友,那這個屬性就要用可變的set來實現。這種情況下,通常應該提供一個readonly屬性供外界使用,返回一個不可變的set,這個set是內部可變set的一份拷貝。比如下面這份代碼:
使用清晰而協調的命名方式
OC當中方法與變量名采用“駝峰式大小寫命名法”,而類名首字母大寫,并且有兩三個前綴字母。
方法命名
命名方法時,應當使方法像個日常用語中的句子,準確傳達方法所執行的任務,然而方法名不能長得太過分,應盡量言簡意賅。
類與協議命名
類與協議的名稱應加上前綴,并且應該像給方法起名一樣組織好詞句,使從左至右比較通順。
為私有方法名加前綴
在編寫私有方法時,最好使用前綴將私有方法標注出來,前綴最好包含下劃線與字母p。
要注意不應該直接使用下劃線作為私有方法的前綴,因為蘋果公司喜歡單用一個下劃線作為私有方法的前綴,使用一個下劃線有可能會無意中覆寫超類中的其他方法。
理解OC錯誤模型
自動引用計數不是“異常安全”的,并且即使不用ARC,也很難寫出在拋出異常時不會導致內存泄漏的代碼。所以OC語言當中,異常只用于極其嚴重的錯誤,拋出異常之后,應用程序應該退出,也就無需考慮恢復問題了。
在出現不那么嚴重的錯誤時,OC語言所用的編程范式為:令方法返回nil/0,或是使用NSError,以表明其中有錯誤發生。
NSError的用法更加靈活,NSError對象里封裝了三條信息:
Error domain:錯誤發生的范圍,也就是產生錯誤的根源。
Error code:獨有的錯誤代碼,用以指明在某個范圍內具體發生了何種錯誤。
User info:有關此錯誤的額外信息。
NSError有兩種常見用法,一種是通過委托協議來傳遞錯誤,另一種是經由方法的“輸出參數”返回給調用者。
理解NSCopying協議
OC中如果想令自己的類支持拷貝操作,那就要實現NSCopying協議,該協議只有一個方法:
這里zone參數不用考慮,使用默認參數即可。比如游客表示個人信息的類,可以聲明遵從NSCopying協議:
有時需要獲取可變的拷貝,則應遵守NSMutableCopying協議,該協議也只定義了一個方法:
當對象需要深拷貝時,可考慮吧新增一個專門執行深拷貝的方法
協議與分類
通過委托與數據源協議進行對象間通信
OC開發中經常使用一種“委托模式”,主旨是:定義一套接口,某對象若想接受另一個對象的委托,則需遵從此接口,以成為其“委托對象”,而這另一個對象,則可以給其委托對象回傳一些信息,也可以在發生相關事件時通知委托對象。一般通過協議來實現委托模式。
用一張圖來演示委托模式的概念:
這里EOCDataModel1就是作為EOCNetwirkFetcher的委托對象。
但是要注意,類中存放委托對象的屬性需定義成weak,而非strong:
@interface EOCNetworkFetcher : NSObject
@property (nonatomic, weak) id <EOCNetworkFetcherDelegate> delegate;
@end
因為通常delegate要持有本對象,若本對象也持有delegate,那么就會引入保留環。
實現委托對象可以在接口中聲明,也可以在“class-continuation分類”中聲明。如果要向外界公布此類實現了某協議,那么就在接口中聲明,如果是委托協議,通常只在類內部使用,一般在"class-continuation分類"里聲明。
還有另一種,令某類經由協議中接口獲取所需的數據,被稱為“數據源模式”。
若有必要,可實現含有位段的結構體,將委托對象是否能相應相關協議方法這一信息緩存至其中。
將類的實現代碼分散到便于管理的數個分類之中
當類中存在大量方法的代碼時,可以通過OC的分類機制,把類代碼按邏輯劃入幾個分區中。
比如下面這個管理個人信息的類:
可以把不同的方法放入不同分類中:
這些分類可以全部放在一個實現文件中,但當存在許多分類時,最好每個分類提取到各自的文件中去。以EOCPerson為例,可以拆分成下列這幾個文件:
私有方法應歸入名叫Private的分類中,以隱藏實現細節。
總是為第三方類的分類名稱加前綴
我們經常通過分類為無源碼的既有類添加方法,這時就容易出現命名沖突的問題。我們應該為分類和方法添加了前綴。
比如為NSString添加分類處理HTTP URL有關的字符串。
我們為其加上前綴:
使用"class-continuation分類"隱藏實現細節
class-continuation分類"和普通的分類不同,他必須定義在其所接續的那個類的實現文件里,這是唯一能聲明實例變量的分類。
這種分類在實現文件中格式如下:
通過這種分類可以獲得隱藏程度更好的私有方法和私有變量。
除了獲得隱藏變量和方法之外,使用這種分類還可以將只讀的屬性擴展為可讀寫的,以便在類的內部設置其值。
還有一種用法是,當對象所遵從的協議只應視為私有,則可在該分類中聲明
通過協議提供匿名對象
有時,我們可以把返回的對象設計為遵從某協議的id類型,這樣的話,想要隱藏的類名就不會出現在API之中了。若接口背后有多個不同的實現類,又不想指明具體使用哪個,可以考慮用這個方法,此概念被稱為“匿名對象”。
有時對象類型不重要,重要的是有沒有實現某些方法,在此情況下,也可以使用這些“匿名類型”來表達這一概念。
比如對受委托者的定義: