我們在寫程序時,都希望其中一部分代碼用于后續(xù)項目塑猖,又或者把某些代碼發(fā)布出來羊苟,供他人使用。因此巍虫,我們構建項目的要注意:
15俯抖、用前綴避免命名空間沖突
- 因為Objective-C沒有其他語言那種內置的命名空間機制(namespace)。
所以我們在起名時要設法避免潛在的命名沖突搔啊,否則就容易重名,發(fā)生命名沖突旧蛾,程序鏈接過程就會出錯锨天。比如下面:
- 避免問題:
變相實現(xiàn)命名空間:為所有名稱都加上適當前綴(一般是與公司或者應用程序有關聯(lián)的名字)。命名時要注意:因為Apple宣傳其保留使用所有“兩字母前綴”的權利益缠,那我們自己選的前綴應該是三個字母的基公。
16欠痴、提供“全能初始化方法”
- 所有對象都要初始化。但是創(chuàng)建類實例的方式有的時候不止一種菩咨。
例如:UITableViewCell,初始化時云茸,需要指明其樣式以及標識符标捺,標識符區(qū)分不同類型的單元格嗤疯。
這種對象的創(chuàng)建成本比較高,繪制表格的時候可依照標識符復用,提升程序效率戴而。我們把這種可為對象提供必要信息以便能完成工作的初始化方法叫做“全能初始化方法” - 試一試
首先創(chuàng)建一個類“ZSCManager”然后給其添加2個只讀的屬性淮逊,這樣外界就無法更改了泄鹏,再提供初始化方法設置這兩個屬性:
#import <Foundation/Foundation.h>
@interface ZSCManager : NSObject
@property (nonatomic, readonly, copy) NSString *name;
@property (nonatomic, readonly, copy) NSString *phone;
- (id)initWithManageName:(NSString *)name
phone:(NSString *)phone;
@end
//.m的實現(xiàn)
#import "ZSCManager.h"
@implementation ZSCManager
- (id)init {
return [self initWithManageName:@"未知名字" phone:@"110"];
}
- (id)initWithManageName:(NSString *)name
phone:(NSString *)phone {
if (self = [super init]) {
_name = name;
_phone = phone;
}
return self;
}
@end
注意:
設置默認值的那個init方法調用了“全能初始化方法”。
若是存儲方式變了(比如名字和手機號放在某個結構中)车猬,則init與全能初始化方法設置數(shù)據的代碼就要修改珠闰。
簡單的情況沒有太大問題伐厌,如果類的初始化方法有很多種军熏,而且初始化的數(shù)據較為復雜衔瓮,那么這樣做就麻煩的多热鞍。很容易忘記修改某個初始化方法澄港,造成初始化方法之間相互不一致祖搓。假如現(xiàn)在創(chuàng)建個名叫 ZSCLeader 的類,讓其成為 ZSCManager 的子類藏姐。那么新類的初始化方法要怎么寫呢该贾?
#import "ZSCManager.h"
@interface ZSCLeader : ZSCManager
- (id)initWithLeaderName:(NSString *)name;
@end
//.m的實現(xiàn)
#import "ZSCLeader.h"
@implementation ZSCLeader
- (id)initWithManageName:(NSString *)name
phone:(NSString *)phone {
return [self initWithLeaderName:name];
}
- (id)initWithLeaderName:(NSString *)name {
return [super initWithManageName:name phone:nil];
}
@end
ZSCLeader類的全能初始化方法調用了超類的全能初始化方法包各,
再看 ZSCManager 類的實現(xiàn),也會發(fā)現(xiàn) ZSCManager 也調用了超類的全能初始化方法靶庙,因此說明:全能初始化的方法調用鏈一點要維系问畅。
調用者創(chuàng)建 ZSCLeader 會通過 initWithLeaderName 或者 init的方法。所以要覆寫超類的全能初始化方法六荒,否則init方法創(chuàng)建就會有問題护姆。有時候我們不想覆寫超類的全能初始化方法,可以理解為:我們認為這是調用者自己犯錯了掏击。這樣子卵皂,我們就需要覆寫超類的全能初始化方法并拋出異常:
- (id)initWithManageName:(NSString *)name
phone:(NSString *)phone {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"不讓你調用此方法,方法名字:initWithManageName:(NSString *)name phone:(NSString *)phone 或者 init" userInfo:nil];
}
然后調用init 或者超類的方法創(chuàng)建時砚亭,程序就會崩潰報錯
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '不讓你調用此方法灯变,方法名字:initWithManageName:(NSString *)name phone:(NSString *)phone 或者 init'我們不想程序崩潰也想知道崩潰的原因殴玛,可以這樣辦:
@try {
// 可能會出現(xiàn)崩潰的代碼
ZSCLeader *leader = [[ZSCLeader alloc] init];
}
@catch (NSException *exception) {
// 捕獲到的異常exception
NSLog(@"%@",exception);
//控制臺的輸出
//不讓你調用此方法,方法名字:initWithManageName:(NSString *)name phone:(NSString *)phone 或者 init
}
@finally {
// 結果處理
}
- 總結:
- 如果在類中提供一個全能初始化方法添祸,在文檔中指明滚粟。其他初始化方法均應調用此方法。
- 若全能初始化方法與超類不同刃泌,則需覆寫超類中的對應方法凡壤。
- 如果超類的初始化方法不適用子類,那么應該覆寫這個超類方法耙替,并在其中拋出異常亚侠。
17、實現(xiàn) description 方法
調試程序時俗扇,經常需要打印并查看對象信息硝烂。一般都是這樣做
ZSCManager *manager = [[ZSCManager alloc] init];
NSLog(@"%@",manager);
可以看到輸出為:
<ZSCManager: 0x610000026b40>
這樣的信息不太有用。只有類的名字和指針地址铜幽。-
我們在類中覆寫 description 方法滞谢。
- (NSString *)description { return [NSString stringWithFormat:@"<%@:%p ,\"name : %@ phone : %@\">",[self class],self,_name,_phone];
}
這次的輸出變得不一樣了,對我們也更有用:
<ZSCManager:0x6080000354e0 ,"name : 未知名字 phone : 110">
- 注意:
- 實現(xiàn) description 方法返回一個有意義的字符串啥酱,用以描述該實例爹凹。
- 若想在調試時打印出更詳盡的對象描述信息,則應該實現(xiàn) debugDescription 方法镶殷。
#18禾酱、盡量使用不可變對象
- 設計類的時候,要充分運用屬性來封裝數(shù)據绘趋。
屬性默認情況是“既可讀又可寫的”(readWrite)
一般來說颤陶,我們有些建模的數(shù)據未必需要改變。這樣我們最好把其屬性設置為readonly陷遮。
@property (nonatomic, readonly, copy) NSString *name;
如果想“暴力”修改滓走,那就通過KVC:
[manager setValue:@"哈哈" forKey:@"name"];
#19、使用清晰而協(xié)調的命名方式
- 方法和變量名使用“駝峰式大小寫命名法”
小寫字母開頭帽馋,其后每個單詞首字母大寫搅方。
類名也用駝峰命名法,不過其字母要大寫绽族,而且前面通常有兩三個前綴字母姨涡。
- 方法名要言簡意賅,從左至右讀起來要像個日常用語中的句子才好吧慢。
- 方法名里不要使用縮略后的類型名稱涛漂。
- 給方法起名時的第一要務就是確保其風格與你自己的代碼或所要集成的框架相符。
#20、為私有方法名加前綴
- 一個類所要做的事情通常都要比外面看到的更多匈仗。
編寫類的實現(xiàn)代碼時瓢剿,經常要寫一些只在內部使用的方法。
建議應該為這種方法的名稱加上某些前綴悠轩。
1间狂、有助于調試。
2哗蜈、容易把公共方法和私有方法區(qū)別開前标。
- 不要單用一個下劃線做私有方法的前綴坠韩,因為這種做法是預留給蘋果公司用的距潘,建議用p_XXXX這樣。p代表 “private”(私有的)只搁。
#21音比、理解Objective-C錯誤模型
- 很多編程語言都有“異常”(exception)機制氢惋,Objective-C 也不例外洞翩。
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"XXX" userInfo:nil];
OC語言現(xiàn)在采用的方法:只在極其罕見的情況下拋出異常,異常拋出之后焰望,無須考慮恢復問題骚亿,應用會立刻退出。不需要編寫“異常安全”代碼熊赖。
- Objective-C在出現(xiàn)“非致命錯誤”時来屠。這樣處理的:
令方法返回 nil/0,或者是使用NSError震鹉。
- 假如調用者發(fā)現(xiàn)方法的返回值是nil俱笛,就可以確定其中發(fā)生了錯誤。就可以采取相對應的措施传趾。
- NSError 用法靈活迎膜。我們可以把導致錯誤的原因匯報給調用者。
NSError domain(錯誤范圍浆兰,類型為字符串)
產生錯誤的根源磕仅,比如從URL中解析或取得數(shù)據時出錯了,就會使用NSURLErrorDomain來表示錯誤范圍簸呈。
Error code(錯誤碼榕订,類型為整數(shù))
獨有的錯誤代碼,錯誤情況通常采用 enum 來定義蝶棋。比如 HTTP 請求出錯時卸亮,可能會把HTTP狀態(tài)碼設為錯誤碼。
User info (用戶信息玩裙,類型為字典)
關于錯誤的額外信息兼贸。
- 參考 AFNetworking 中對NSError的使用段直,直接把錯誤信息放在 NSError 對象里,經由“輸出參數(shù)”返回給調用者溶诞。
#22鸯檬、理解 NSCopying 協(xié)議
- 使用對象時經常需要拷貝它。
在Objective-C中螺垢,如果想令自己的類支持拷貝操作喧务,就要實現(xiàn) NSCopying 協(xié)議。協(xié)議里只有一個方法:
- (id)copyWithZone:(nullable NSZone *)zone
NSZone是什么呢枉圃?
以前開發(fā)程序時功茴,會把內存分為不同的“區(qū)”(zone),對象會創(chuàng)建在某個區(qū)里面孽亲。
現(xiàn)在不用了坎穿,每個程序只有一個“默認區(qū)”,不用擔心其中的 zone 參數(shù)返劲。
- (id)copyWithZone:(nullable NSZone *)zone {
ZSCManager *copy = [[[self class] allocWithZone:zone] initWithManageName:_name phone:_phone];
return copy;
}
直接把待拷貝的對象交給“全能初始化方法”玲昧,令其執(zhí)行所有初始化工作。
- 若是自定義的對象分為可變版本和不可變版本篮绿,那么就要同時實現(xiàn) NSCopying 和 NSMutableCopying 協(xié)議孵延。
- 復制對象時需要決定采用淺拷貝還是深拷貝,一般情況下執(zhí)行淺拷貝亲配。
深拷貝:在拷貝自身時尘应,將其底層數(shù)據也一并復制過來。
淺拷貝:只拷貝容器對象本身弃榨,而不復制其中數(shù)據菩收。
注意:容器內的對象未必都能拷貝,調用者也不一定想在拷貝容器的時候一并拷貝其中的每個對象鲸睛。
因為:沒有專門定義深拷貝的協(xié)議娜饵。
所以:具體執(zhí)行方式由每個類來確定,只需要你自己決定自己寫的類是否要提供深拷貝的方法官辈。如果你所寫的對象需要深拷貝箱舞,那么可以考慮新增一個專門執(zhí)行深拷貝的方法。
### 接下來也將會繼續(xù)整理拳亿。如果覺得有用請點個喜歡晴股!
### 您的支持將是我繼續(xù)寫作的動力!謝謝肺魁。
[觀“編寫高質量iOS與OC X代碼的52個有效方法”有感(一)· 熟悉Objective-C](http://www.reibang.com/p/0876e60d3160)
[觀“編寫高質量iOS與OC X代碼的52個有效方法”有感(二)· 對象电湘、消息、運行時](http://www.reibang.com/p/1aac4fb98888)
[觀“編寫高質量iOS與OC X代碼的52個有效方法”有感(三)· 接口與API設計](http://www.reibang.com/p/5d9e61db2a01)
[觀“編寫高質量iOS與OC X代碼的52個有效方法”有感(四)· 協(xié)議與分類](http://www.reibang.com/p/0944e1e276ff)