三、接口與API設(shè)計(jì)
15. 用前綴避免命名空間沖突
- 選擇公司、應(yīng)用程序、其一二之名作為類名的前綴,并在所有代碼均使用這一前綴
- 為項(xiàng)目中使用第三方庫(kù)加上前綴。(一般不用)
OC 沒(méi)有內(nèi)置的命名空間(namespace)機(jī)制,所以如果命名重名,就會(huì)發(fā)送命名沖突(naming calsh)項(xiàng)目報(bào)錯(cuò)。
重命名符號(hào)錯(cuò)誤(duplicate symbol error)報(bào)錯(cuò):
duplicate symbol _OBJC_METACLASS_$_EOCTheClass in:
build/something.o
build/something_else.o
duplicate symbol _OBJC_CLASS_$_EOCTheClass in:
build/something.o
build/something_else.o
解決方案:
- 所有名稱都加上適量前綴。
- 使用3字母 != Apple Cocoa(兩字母前綴 two_letter prefix)。
16. 提供“全能初始化方法”
- 在類中提供一個(gè)全能初始化方法,并在文檔中指明。其他初始化方法均調(diào)用次方法。
- 若全能初始化方法與超類不同, 則需要覆寫(xiě)超類中對(duì)應(yīng)的方法
- 超類的初始化不適用子類,應(yīng)該覆寫(xiě)超類的方法,并在其中拋出異常。
全能初始化(指定初始化方法)(designated initializer):對(duì)象提供必要信息以便其能完成工作的初始化方法。
這個(gè)類多個(gè)初始化方法,其他初始化方法調(diào)用全能初始化。
覆寫(xiě)父類的全能初始化方法并在其中拋出異常:
-(id) initWithWidth:(float)width andHeight:(float)height{
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Must use initWithDimension: instead." userInfo:nil];
}
17. 實(shí)現(xiàn)description方法
- 實(shí)現(xiàn)description方法返回有意義的字符串,用以描述該實(shí)例。
- 調(diào)試時(shí)候打?。簩?shí)現(xiàn)debugDescription方法。
在類里添加實(shí)現(xiàn)方法 description、 debugDescription
-(NSString *)description{
return [NSString stringWithFormat:@"%@, %@",[self class], self];
}
-(NSString *)debugDescription{
return [NSString stringWithFormat:@"%@, %@",[self class], self];
}
18. 盡量使用不可變對(duì)象
- 盡量創(chuàng)建不可變的對(duì)象。
- 某些屬性僅可用于對(duì)象內(nèi)部修改,則在“calss-continuation 分類” 中將其由readonly屬性擴(kuò)張為readwrite屬性。
- 不要把可變的collection作為屬性公開(kāi),而應(yīng)提供相關(guān)的方法,以此修改對(duì)象中可變的collection。
例子: 在類 head 里實(shí)現(xiàn)readonly 在“calss-continuation 分類” readwrite。
@interface CustomViewController:UIViewController
@property(nonatomic, copy, readonly) NSString* identifier;
@end
@interface CustomViewController ()
@property(nonatomic, copy, readwrite) NSString* identifier;
@end
19. 使用清晰而協(xié)調(diào)的命名方式
- 遵從標(biāo)準(zhǔn)的Object-C 命名規(guī)范。
- 言簡(jiǎn)意駭,從左至右讀起來(lái)要像個(gè)日常用語(yǔ)(最好)
- 不要使用縮略后的類型
- 風(fēng)格符合自己的代碼或者集成的框架。
方法和命名:
- 駝峰式大小寫(xiě)命名發(fā)(camel casing):小寫(xiě)字母開(kāi)頭、其后沒(méi)有單詞首字母大寫(xiě)。
- 類名也用駝峰,不過(guò)都要首字母要大寫(xiě)。
方法命名例子:
+string
+stringWithString
+localizedStringWithFormat:
-lowercaseString
-intValue
-length
-lengthOfBytesUsingEncoding:
-getCharacters:range:
-(void)getCharacters:(unichar*)buffer range:(NSRange)aRange
-hasPrefix
-isEqualToString:
類和協(xié)議的命名:
- 加上前綴。 例如: UIView、UIViewController..
- 在類名后面加上Delegate 例如:UITableViewDelegate
20. 為私有方法添加前綴
- 私有方法加上前綴區(qū)別公有方法
- 不要單用"_" 來(lái)做私有方法的前綴,這種做法是預(yù)留給apple 公司的。
私有方法添加前綴: "p_"
-(void)p_privateMethod{}
21. 理解Object-C 錯(cuò)誤模型
- 只在及其罕見(jiàn)的情況下才會(huì)拋出異常,程序直接退出。
- 不那么嚴(yán)重的錯(cuò)誤: 方法放回 nil/0, 或是使用NSError 表明有錯(cuò)誤發(fā)生。
NSError 三條信息:
- Error domain (錯(cuò)誤范圍, type : NSString)
- Error code (錯(cuò)誤碼, type: int)
- user info (用戶信息, type: dictionary)
NSError 常見(jiàn)用法
1.由(delegate) 來(lái)傳遞
-(void)connection:(NSURLConnection*) connection didFailWithError:(NSError*) error
2.由方法的“輸出參數(shù)” 放回給調(diào)用者,不僅能通過(guò)返回值判斷是否成功,還通過(guò)NSError來(lái)判定
-(BOOL)doSomething:(NSError**)error
NSError *error = nil;
BOOL ret = [object doSomething:&error];
if(error){
//There was an error
}
BOOL ret = [object doSomething:nil];
if (ret){
//there was an error
}
3.例子
-(BOOL)doSomething:(NSError **)error{
//Do Something that my cause an error
if(/* there was an error */){
if (error){
//Pass the 'error' through the out-parameter
*error = [NSError errorWithDmain:domain code:code userinfo:userInfo];
}
return NO;
}else {
return YES;
}
}
22. 理解NSCoping 協(xié)議
- 若自定義對(duì)象具有拷貝功能,需實(shí)現(xiàn)NSCopying 協(xié)議
- 根據(jù)對(duì)象類型 : 可變、不可變 -> NSCopying 與 NSMuatbleCoping
- 淺拷貝、深拷貝(若需要,則考慮新增一個(gè)專門執(zhí)行深拷貝的方法), 一般情況應(yīng)該盡量使用淺拷貝。
兩個(gè)拷貝協(xié)議 NSCopying、NSMutableCopying:
- (id)copyWithZone:(nullable NSZone *)zone;
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
例子:
-(id)copyWithZone:(NSZone *)zone{
Person* copy = [[[self class] allocWithZone:zone] initWithFirstName:_firstName];
copy->_friends = [_friends mutableCopy];
return
}
"->" 語(yǔ)法:內(nèi)部使用實(shí)例變量。