一. 格式化代碼
1. 指針“*”號的位置
? 如:NSString *varName;
2. 空格 VS tabs
? 只允許使用空格,將編輯器設(shè)置為1個(gè)TAB = 2個(gè)字符縮進(jìn)
3. 每行的長度
? 每行最多不得超過100個(gè)字符
? 以15寸Macbook Pro的大小,每行100個(gè)字符時(shí)能最大化地同時(shí)容下編輯器和iPhone模擬器
? Google的80字符的標(biāo)準(zhǔn)有點(diǎn)少瘫想,這導(dǎo)致過于頻繁的換行(Objectve-C的代碼一般都很長)
? 通過 “Xcode => Preferences => TextEditing => 勾選Show Page Guide / 輸入
100 => OK” 來設(shè)置提醒
4. 方法的聲明和定義
? 在 - OR + 和返回值之間留1個(gè)空格丛晌,方法名和第一個(gè)參數(shù)間不留空格堵第。如:
- (void)doSomethingWithString:(NSString *)theString {
...
}
//當(dāng)參數(shù)過長時(shí),每個(gè)參數(shù)占用一行沫屡,以冒號對齊拌牲。如:
- (void)doSomethingWith:(GTMFoo *)theFoo
rect:(NSRect)theRect
interval:(float)theInterval {
...
}
? 如果方法名比參數(shù)名短俱饿,每個(gè)參數(shù)占用一行,至少縮進(jìn)4個(gè)字符们拙,且為垂直對齊(而非使用冒號
對齊)稍途。如:
- (void)short:(GTMFoo *)theFoo
longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval {
...
}
5. 方法的調(diào)用
? 調(diào)用方法沿用聲明方法的習(xí)慣阁吝。例外:如果給定源文件已經(jīng)遵從某種習(xí)慣砚婆,繼續(xù)遵從那種習(xí)慣。
? 所有參數(shù)應(yīng)在同一行中突勇,或者每個(gè)參數(shù)占用一行且使用冒號對齊装盯。如:
[myObject doFooWith:arg1 name:arg2 error:arg3];
或
[myObject doFooWith:arg1
name:arg2
error:arg3];
? 和方法的聲明一樣,如果無法使用冒號對齊時(shí)甲馋,每個(gè)參數(shù)一行埂奈、縮進(jìn)4個(gè)字符、垂直對其(而非
使用冒號對齊)定躏。如:
[myObj short:arg1
longKeyword:arg2
evenLongerKeyword:arg3];
6. @public 和 @private
? @public 和 @private使用單獨(dú)一行账磺,且縮進(jìn)1個(gè)字符
7. Protocals
? 類型標(biāo)示符芹敌、代理名稱、尖括號間不留空格垮抗。
? 該規(guī)則同樣適用于:類聲明氏捞、實(shí)例變量和方法聲明。如:
@interface MyProtocoledClass : NSObject<NSWindowDelegate> {
@private
id<MyFancyDelegate> _delegate;
}
- (void)setDelegate:(id<MyFancyDelegate>)aDelegate;
@end
? 如果類聲明中包含多個(gè)protocal冒版,每個(gè)protocal占用一行液茎,縮進(jìn)2個(gè)字符。如:
@interface CustomViewController : ViewController<
AbcDelegate,
DefDelegate
> {
...
}
二. 命名
1. 類名
? 類名(及其category name
和 protocol name
)的首字母大寫辞嗡,寫使用首字母大寫的形式
2. 分割單詞
? 在面向特定應(yīng)用的代碼中捆等,類名應(yīng)盡量避免使用前綴,每個(gè)類都使用相同的前綴影響可讀性续室。
? 在面向多應(yīng)用的代碼中栋烤,推薦使用前綴。如:GTMSendMessage
3. 方法名
? 方法名的首字母小寫挺狰,且使用首字母大寫的形式分割單詞班缎。方法的參數(shù)使用相同的規(guī)則。
? 方法名+參數(shù)應(yīng)盡量讀起來像一句話(如:)她渴。在這里查看蘋果對方法命名的規(guī)范达址。
? getter的方法名和變量名應(yīng)相同。不允許使用“get”前綴趁耗。如:
- (id) getDelegate; // 禁止
- (id)delegate; // 對頭
? 本規(guī)則僅針對Objective-C代碼沉唠,C++代碼使用C++的習(xí)慣
4. 變量名
? 變量名應(yīng)使用容易意會(huì)的應(yīng)用全稱,且首字母小寫苛败,且使用首字母大寫的形式分割單詞
? 成員變量使用“”作為前綴(如:“NSString *_varName;
”满葛。雖然這與蘋果的標(biāo)準(zhǔn)相沖突,但基于以下原因罢屈,仍使用“”作為前綴嘀韧。 )
? 使用“_”作為前綴,更容易在有代碼自動(dòng)補(bǔ)全功能的IDE中區(qū)分“屬性
(self.userInfo
)”和“成員變量(_userInfo
)”
? 常量(#define, enums, const等)使用小寫“k”作為前綴缠捌,首字母大寫來分割單詞锄贷。如:
kInvalidHandle
三. Cocoa 和 Objective-C特有的規(guī)則
1. 成員變量使用 @private。如:
@interface MyClass : NSObject {
@private
id _myInstanceVariable;
}
// public accessors, setter takes ownership
- (id)myInstanceVariable;
- (void)setMyInstanceVariable:(id)theVar;
@end
2. 初始化
? 在初始化方法中曼月,不要將變量初始化為“0”或“nil”谊却,那是多余的
? 內(nèi)存中所有的新創(chuàng)建的對象(isa除外)都是0,所以不需要重復(fù)初始化為“0”或“nil”
3. 避免顯式的調(diào)用 +new 方法
? 禁止直接調(diào)用 NSObject 的類方法 +new哑芹,也不要在子類中重載它炎辨。使用alloc和init方法
4. 保持公共API的簡潔性
5. #import VS #include
? 使用 #import
引入Ojbective-C
和Ojbective-C++
頭文件,使用 #include
引入C
和C++
頭
文件
6. import 根框架(root frameworks)聪姿,而非各單個(gè)文件
? 雖然有時(shí)我們僅需要框架(如Cocoa 或 Foundation
)的某幾個(gè)頭文件碴萧,但引入根文件,編譯器會(huì)運(yùn)行的更快乙嘀。因?yàn)楦蚣埽?code>root frameworks)一般會(huì)預(yù)編譯,所以加載會(huì)更快破喻。再次強(qiáng)
調(diào):使用 #import 而非 #include 來引入Objective-C框架乒躺。如:
#import <Foundation/NSArray.h> // 禁止
#import <Foundation/NSString.h>
...
#import <Foundation/Foundation.h> // 對頭
7. 創(chuàng)建對象時(shí)盡量使用autorelease
? 創(chuàng)建臨時(shí)對象時(shí),盡量同時(shí)在同一行中 autorelease
掉低缩,而非使用單獨(dú)的 release
語句
? 雖然這樣會(huì)稍微有點(diǎn)慢嘉冒,但這樣可以阻止因?yàn)樘崆?return
或其他意外情況導(dǎo)致的內(nèi)存泄露。
通盤來看這是值得的咆繁。如:
// 避免這樣使用(除非有性能的考慮)
MyController* controller = [[MyController alloc] init];
// ... 這里的代碼可能會(huì)提前return ...
[controller release];
// 這樣更好
MyController* controller = [[[MyController alloc] init] autorelease];
8. 先autorelease
讳推,再retain
? 在為對象賦值時(shí),遵從“先autorelease
玩般,再retain
”
? 在將一個(gè)新創(chuàng)建的對象賦給變量時(shí)银觅,要先將舊對象release
掉,否則會(huì)內(nèi)存泄露坏为。市面上有很多方法來handle這種情況究驴,這里選擇“先autorelease
,再retain
”的方法匀伏,這種方法不易引入error
洒忧。注意:在循環(huán)中這種方法會(huì)“填滿”autorelease pool
,稍稍影響效率够颠,但是
Google和我( :P )認(rèn)為這個(gè)代價(jià)是可以接受的熙侍。如:
- (void)setFoo:(GMFoo *)aFoo {
[foo_ autorelease]; // 如果foo_和aFoo是同一個(gè)對象(foo_ == aFoo),dealloc不會(huì)被調(diào)用
foo_ = [aFoo retain];
}
9. dealloc的順序要與變量聲明的順序相同
? 這有利于review代碼
? 如果dealloc中調(diào)用其他方法來release變量,將被release的變量以注釋的形式標(biāo)注清楚
10. NSString
的屬性的setter
使用“copy
”
? 禁止使用retain
履磨,以防止意外的修改了NSString
變量的值蛉抓。如:
- (void)setFoo:(NSString *)aFoo {
[foo_ autorelease];
foo_ = [aFoo copy];
}
或
@property (nonatomic, copy) NSString *aString;
11. 避免拋出異常(Throwing Exceptions
)
12. 對 nil
的檢查
? 僅在有業(yè)務(wù)邏輯需求時(shí)檢查 nil,而非為了防止崩潰
? 向 nil 發(fā)送消息不會(huì)導(dǎo)致系統(tǒng)崩潰剃诅,Objective-C運(yùn)行時(shí)負(fù)責(zé)處理巷送。
13. BOOL 陷阱
? 將int
值轉(zhuǎn)換為BOOL
時(shí)應(yīng)特別小心。避免直接和YES
比較
? Objective-C
中矛辕,BOOL
被定義為unsigned char
笑跛,這意味著除了YES (1)
和 NO (0)
外它還可以是其他值。禁止將int
直接轉(zhuǎn)換(cast or convert)為BOOL
如筛。
? 常見的錯(cuò)誤包括:將數(shù)組的大小堡牡、指針值或位運(yùn)算符的結(jié)果轉(zhuǎn)換(cast or convert)
為 BOOL
抒抬,因?yàn)樵?code>BOOL值的結(jié)果取決于整型值的最后一位
? 將整型值轉(zhuǎn)換為BOOL
的方法:使用三元運(yùn)算符返回YES / NO
杨刨,或使用位運(yùn)算符(&&, ||, !)
? BOOL
、_Bool
和bool
之間的轉(zhuǎn)換是安全的擦剑,但是BOOL
和Boolean
間的轉(zhuǎn)換不是安全的妖胀,所以將Boolean
看成整型值芥颈。
? 在 Objective-C 中,只允許使用BOOL
? 如:
// 禁止
- (BOOL)isBold {
return [self fontTraits] & NSFontBoldTrait;
}
- (BOOL)isValid {
return [self stringValue];
}
// 對頭
- (BOOL)isBold {
return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;
}
- (BOOL)isValid {
return [self stringValue] != nil;
}
- (BOOL)isEnabled {
return [self isValid] && [self isBold];
}
? 禁止直接將BOOL
和YES/NO
比較赚抡,如:
// 禁止
BOOL great = [foo isGreat];
if (great == YES)
...
// 對頭
BOOL great = [foo isGreat];
if (great)
...
14. 屬性
? 命名:與去掉“_”
前綴的成員變量相同爬坑,使用@synthesize
將二者聯(lián)系起來。如:
// abcd.h
@interface MyClass : NSObject {
@private
NSString *_name;
}
@property (copy, nonatomic) NSString *name;
@end
// abcd.m
@implementation MyClass
@synthesize name = _name;
@end
? 位置:屬性的聲明緊隨成員變量塊之后涂臣,中間空一行盾计,無縮進(jìn)。如上例所示
? 嚴(yán)把權(quán)限:對不需要外部修改的屬性使用readonly
? NSString
使用copy
而非retain
? CFType
使用@dynamic
, 禁止使用@synthesize
? 除非必須赁遗,使用nonatomic
? Cocoa Pattern
15. Delegate Pattern(委托)
? delegate
對象使用assign
署辉,禁止使用retain
。因?yàn)?code>retain會(huì)導(dǎo)致循環(huán)索引導(dǎo)致內(nèi)存泄露,并且此類型的內(nèi)存泄露無法被Instrument
發(fā)現(xiàn)岩四,極難調(diào)試 .
? 成員變量命名為_delegate
哭尝,屬性名為delegate
16. Model/View/Controller
? Model
和View
分離
? Controller
獨(dú)立于View
和Controller
? 不要在與view
相關(guān)的類中添加過多的業(yè)務(wù)邏輯代碼,這讓代碼的可重用性很差
? Controller
負(fù)責(zé)業(yè)務(wù)邏輯代碼剖煌,且Controller
的代碼與view
盡量無關(guān)
? 使用 @protocal
定義回調(diào)APIs
材鹦,如果并非所有方法都是必須的,使用@optional
標(biāo)示