第15條:用前綴避免命名空間沖突
- 選擇與你的公司场仲,應(yīng)用程序或二者皆有關(guān)聯(lián)之名稱作為類名的前綴萌丈,并在所有代碼中使用這以前綴赎瞎,包括純C函數(shù)及全局變量撵渡。前綴應(yīng)該以三個(gè)大寫字母為前綴融柬,用前綴還有一個(gè)好處,就是有些app在混淆代碼的時(shí)候趋距,很方便快捷的混淆自己的iOS代碼粒氧。
- 若自己開發(fā)的應(yīng)用程序需要為其他程序提供插件支持,那么自己的開發(fā)的應(yīng)用程序中使用到的第三方插件也需要修改其前綴节腐。
- 此條看到了一個(gè)符號表外盯,此表的功能是顯示iOS文件的文件名,函數(shù)名翼雀,行數(shù)等饱苟。由此找到騰訊的Bugly插件,此插件可以在iOSAPP發(fā)布后狼渊,如果APP發(fā)生crash箱熬,或是卡頓等問題,可以及時(shí)查看到問題,定位問題很準(zhǔn)確城须,且還有解決方案蚤认。
參考地址Bugly
第16條:提供“全能初始化方法”
- 對于提供多個(gè)初始化方法的類,應(yīng)該提供一個(gè)全能的初始化方法糕伐,其他初始化方法以此方法為基礎(chǔ)進(jìn)行擴(kuò)展砰琢。
2 在全能初始化方法里進(jìn)行存儲數(shù)據(jù)等,如果有存儲機(jī)制改變等原有只需修改全能初始化方法即可良瞧。 - 若全能初始化方法與超類不同氯析,則需覆寫超類中的
對應(yīng)方法
。--強(qiáng)調(diào)對應(yīng)的方法莺褒,不是亂調(diào)用方法掩缓。 - 如果超類的初始化方法不適用于子類,那么應(yīng)該覆寫這個(gè)超類方法遵岩,并在其中拋出異常你辣。
第17條:實(shí)現(xiàn)description方法
- 實(shí)現(xiàn)decription方法返回一個(gè)有意義的字符串,用以描述該實(shí)例尘执。
- 若想在調(diào)試時(shí)打印更詳盡的對象描述舍哄,則應(yīng)實(shí)現(xiàn)debugDescription方法。
第18條:盡量使用不可變對象
- 在公共接口中(
.h文件
)聲明屬性的時(shí)候誊锭,盡量使用不可變對象表悬。 - 在公共接口中,集合使用不可變對象時(shí)丧靡,盡量使用
readonly
特征修飾蟆沫,且提供相應(yīng)的增加移除方法,并重寫屬性的get
方法温治。
情況一
.h
文件
@interface WCCPerson : NSObject
@property (nonatomic, copy) NSString *myName;
@property (nonatomic, copy, readonly)NSArray *friends;
- (instancetype)initWithName:(NSString *)myName;
@end
@interface NSArray (WCCPerson)
- (NSString *)toString;
@end
.m
文件
@interface WCCPerson ()
@property (nonatomic, copy, readwrite)NSArray *friends;//將對外的屬性中的readonly饭庞,改成readwrite
@end
@implementation WCCPerson
- (instancetype)initWithName:(NSString *)myName{
if (self = [super init]) {
_myName = [myName copy];
_friends = @[@"json", @"mike"];
}
return self;
}
- (NSArray *)friends{
return _friends;
}
@end
@implementation NSArray (WCCPerson)
- (NSString *)toString{
NSMutableString *string = [NSMutableString string];
for (NSUInteger i = 0; i < [self count]; i++) {
[string appendFormat:@"array[%lu] value is %@, ", (unsigned long)i, self[i]];
}
return [string copy];
}
@end
如果按照上面的寫法也是可以的,對象內(nèi)部操作_friends
屬性熬荆,對象內(nèi)部對屬性進(jìn)行賦值舟山,只允許外部獲取。但這樣有一些問題卤恳,如果用戶使用如下方式累盗,則該寫法有些漏洞。
WCCPerson *person = [[WCCPerson alloc] initWithName:@"wencun"];
NSArray *array = @[@1, @2];
[person setValue:array forKey:@"friends"];
// person.friends =
NSLog(@"%@",person.friends.toString);
//輸出
2017-08-18 11:46:09.011585+0800 WCCTestProj[11807:270808] array[0] value is 1, array[1] value is 2,
雖然這樣并不合法突琳,但用戶一旦這樣操作若债,那么將不可避免。
用戶也可能直接用類型信息查詢功能查出屬性所對應(yīng)的實(shí)例變量在內(nèi)存布局中的偏移量本今,以此來認(rèn)為設(shè)置這個(gè)實(shí)例變量的值拆座。這種也不符合規(guī)范主巍。
情況二
.h
文件
@interface WCCPerson : NSObject
@property (nonatomic, copy) NSString *myName;
@property (nonatomic, copy, readonly)NSArray *friends;
- (instancetype)initWithName:(NSString *)myName;
- (void)addFriends:(NSArray *)objects;
- (void)removeFriends:(NSArray *)objects;
@end
@interface NSArray (WCCPerson)
- (NSString *)toString;
@end
.m
文件
@interface WCCPerson (){
NSMutableArray *mutableFriends;
}
//@property (nonatomic, copy, readwrite)NSArray *friends;
@end
@implementation WCCPerson
- (instancetype)initWithName:(NSString *)myName{
if (self = [super init]) {
_myName = [myName copy];
mutableFriends = [NSMutableArray new];
}
return self;
}
- (void)addFriends:(NSArray *)objects{
[mutableFriends addObject:objects];
}
- (void)removeFriends:(NSArray *)objects{
[mutableFriends removeObject:objects];
}
- (NSArray *)friends{
return [mutableFriends copy];
}
@end
這種寫法可以避免使用setValue:forKey:
設(shè)置后,獲取到自己設(shè)置的值挪凑,因?yàn)槿绻皇褂脤ο筇峁┑姆椒?code>addFriends:孕索,是獲取不到用戶自己設(shè)置的正確的值的,這種情況就迫使用戶使用對象提供的方法來設(shè)置值躏碳。
也可以減少用戶對屬性的操作搞旭,起到封裝屬性的作用了。
第19條:使用清晰而協(xié)調(diào)的命名方式
第20條:為私有方法名加前綴
- 給私有方法的名稱加上前綴菇绵,這樣可以很容易地將其同公共方法區(qū)分開
- 不要單用一個(gè)下劃線做私有方法的前綴肄渗,因?yàn)檫@種做法是預(yù)留給蘋果公司的。
第21條:理解Object-C錯(cuò)誤模型
- 只有發(fā)生了可使整個(gè)應(yīng)用程序崩潰的嚴(yán)重錯(cuò)誤時(shí)咬最,才應(yīng)使用異常翎嫡。此時(shí)無須考慮恢復(fù)的問題,而且應(yīng)用程序此時(shí)也應(yīng)該退出永乌。也就是說不用再編寫“異常安全”代碼了惑申。
id someResource = nil;
if (1) {
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"參數(shù)異常" userInfo:@{}];
}
[someResource release];
- 在錯(cuò)誤不那么嚴(yán)重的情況下,可以指派“委托方法”(delegate method)來處理錯(cuò)誤翅雏,也可以把錯(cuò)誤信息放在NSError對象里圈驼,經(jīng)由“輸出參數(shù)”返回給調(diào)用者。
- 在設(shè)計(jì)API時(shí)望几,NSError的第一種常見的用法是通過委托協(xié)議來傳遞此錯(cuò)誤的绩脆,有錯(cuò)誤發(fā)生時(shí),當(dāng)前對象會把錯(cuò)誤信息經(jīng)由協(xié)議中的某個(gè)方法傳遞給委托對象(delegate)橄抹。如下靴迫,NSURLConnection在委托協(xié)議中NSURLConnectionDelegate中定義了如下方法。
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
-
NSError的另外一種常見的用法是:經(jīng)由方法的“輸出參數(shù)”返回給調(diào)用者害碾,如下:
.h
文件
- (BOOL)doSomething:(NSError *__autoreleasing *)error;
.m
文件
- (BOOL)doSomething:(NSError *__autoreleasing *)error{
NSLog(@"我在這里了doSomething");
if (error) {
*error = [NSError errorWithDomain:NSURLErrorKey code:0 userInfo:@{@"error":@"你錯(cuò)啦....."}];
return NO;
}
return YES;
}
使用ARC時(shí)矢劲,編譯器會把方法簽名中的NSError **
轉(zhuǎn)換成NSError *__autoreleasing *
,也就是說,指針?biāo)傅膶ο髸诜椒▓?zhí)行完畢后自動(dòng)釋放慌随,這個(gè)對象必須自動(dòng)釋放,因?yàn)樵摲椒ǖ恼{(diào)用者躺同,不能保證他自己會釋放掉此方法創(chuàng)建的NSError,所以必須加入autorelase阁猜。
當(dāng)error為nil時(shí),如果不加判斷會報(bào)錯(cuò)蹋艺。
第22條:理解NSCopying協(xié)議
- 若想令自己所寫的對象具有拷貝功能剃袍,則需要實(shí)現(xiàn)NSCopying協(xié)議。
- 如果自定義的對象分為可變版本和不可變版本捎谨,那么就要同時(shí)實(shí)現(xiàn)NSCopying與NSMutableCopying協(xié)議民效。
- 復(fù)制對象時(shí)需要決定采用深拷貝還是淺拷貝憔维,一般情況下應(yīng)該盡量執(zhí)行淺拷貝。
- 如果你所寫的對象需要深拷貝畏邢,那么可考慮新增一個(gè)專門執(zhí)行深拷貝的方法业扒。
文中一段說:深拷貝的意思是:在拷貝對象自身時(shí),將其底層數(shù)據(jù)也一并復(fù)制過去舒萎。Foundation框架中的所有collection類在默認(rèn)情況下都執(zhí)行淺拷貝程储,也就是說,只拷貝容器對象本身臂寝,而不復(fù)制其中的數(shù)據(jù)章鲤。這樣做的主要原因在于,容器內(nèi)的對象未必都能拷貝咆贬,而且調(diào)用者也未必想在拷貝容器時(shí)一并拷貝其中的每個(gè)對象败徊。
NSMutableArray *element = [[NSMutableArray alloc] initWithObjects:@"1", nil];
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithObjects:element, nil];
//此處復(fù)制過后,確實(shí)指針變成新的了掏缎,似乎是產(chǎn)生了一個(gè)新對象集嵌。
NSMutableArray *copyMutableArray = [mutableArray mutableCopy];
NSLog(@"element is %p,mutableArray is %p,copyMutableArray is %p",element, mutableArray, copyMutableArray);
NSLog(@"element is %@,mutableArray is %@,copyMutableArray is %@",element, mutableArray, copyMutableArray);
//此處復(fù)制后,三個(gè)變量的值都變了
[element addObject:@"2"];
NSLog(@"============");
NSLog(@"element is %p,mutableArray is %p,copyMutableArray is %p",element, mutableArray, copyMutableArray);
NSLog(@"element is %@,mutableArray is %@,copyMutableArray is %@",element, mutableArray, copyMutableArray);
輸出結(jié)果
2017-08-21 11:49:39.730755+0800 WCCTestProj[1678:161529] element is 0x600000443f90,mutableArray is 0x6000004443b0,copyMutableArray is 0x600000443ff0
2017-08-21 11:49:39.730991+0800 WCCTestProj[1678:161529] element is (
1
),mutableArray is (
(
1
)
),copyMutableArray is (
(
1
)
)
2017-08-21 11:49:39.731094+0800 WCCTestProj[1678:161529] ============
2017-08-21 11:49:39.731186+0800 WCCTestProj[1678:161529] element is 0x600000443f90,mutableArray is 0x6000004443b0,copyMutableArray is 0x600000443ff0
2017-08-21 11:49:39.731402+0800 WCCTestProj[1678:161529] element is (
1,
2
),mutableArray is (
(
1,
2
)
),copyMutableArray is (
(
1,
2
)
)