正文:
• 格式化代碼
◦ 指針“*”號的位置
▪ 如:NSString *varName;
◦ 空格
VS tabs
▪ 只允許使用空格,將編輯器設置爲1個TAB
= 2個字符縮進
◦ 每行的長度
-
▪ 每行最多不得超過100個字符
-
▪ 以15寸Macbook Pro的大小,每行100個字符時能最大化地同時容下編輯器和iPhone模擬器
-
▪ Google的80字符的標準有點少,這導致過於頻繁的換行(Objectve-C的代碼一般都很長)
-
▪ 通過 “Xcode => Preferences => TextEditing => 勾選Show Page Guide / 輸入
100 => OK” 來設置提醒◦ 方法的聲明和定義
-
▪ 在 - OR + 和返回值之間留1個空格,方法名和第一個參數間不留空格。如:- (void)doSomethingWithString:(NSString *)theString {
...}
-
▪ 當參數過長時,每個參數佔用一行,以冒號對齊。如:- (void)doSomethingWith:(GTMFoo *)theFoo
rect:(NSRect)theRect interval:(float)theInterval {
...}
-
▪ 如果方法名比參數名短,每個參數佔用一行,至少縮進4個字符,且爲垂直對齊(而非使用冒號對齊)。如:
- (void)short:(GTMFoo *)theFoolongKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval { ...
}
◦ 方法的調用
-
▪ 調用方法沿用聲明方法的習慣。例外:如果給定源文件已經遵從某種習慣,繼續遵從那種習慣。
-
▪ 所有參數應在同一行中,或者每個參數佔用一行且使用冒號對齊。如:
[myObject doFooWith:arg1 name:arg2 error:arg3];
或
[myObject doFooWith:arg1 name:arg2
error:arg3];
-
▪ 和方法的聲明一樣,如果無法使用冒號對齊時,每個參數一行、縮進4個字符、垂直對其(而非使用冒號對齊)。如:
[myObj short:arg1longKeyword:arg2
evenLongerKeyword:arg3];
◦ @public 和 @private
▪ @public 和 @private使用單獨一行,且縮進1個字符
◦ Protocals
-
▪ 類型標示符、代理名稱、尖括號間不留空格。
-
▪ 該規則同樣適用於:類聲明、實例變量和方法聲明。如:
@interface MyProtocoledClass : NSObject<NSWindowDelegate> { @private
id<MyFancyDelegate> _delegate; }
- (void)setDelegate:(id<MyFancyDelegate>)aDelegate;
@end
-
▪ 如果類聲明中包含多個protocal,每個protocal佔用一行,縮進2個字符。如:@interface CustomViewController : ViewController<
AbcDelegate,
DefDelegate>{
...}
•命名
◦ 類名
-
▪ 類名(及其category name 和 protocal name)的首字母大寫,寫使用首字母大寫的形式分割單詞
-
▪ 在面向特定應用的代碼中,類名應儘量避免使用前綴,每個類都使用相同的前綴影響可讀性。
-
▪ 在面向多應用的代碼中,推薦使用前綴。如:GTMSendMessage◦ Category Name
▪ 待完善◦ 方法名
-
▪ 方法名的首字母小寫,且使用首字母大寫的形式分割單詞。方法的參數使用相同的規則。
-
▪ 方法名+參數應儘量讀起來像一句話(如:)。在這裏查看蘋果對方法命名的規範。
-
▪ getter的方法名和變量名應相同。不允許使用“get”前綴。如:
- (id) getDelegate; // 禁止
- (id)delegate; // 對頭
-
▪ 本規則僅針對Objective-C代碼,C++代碼使用C++的習慣
◦ 變量名
-
▪ 變量名應使用容易意會的應用全稱,且首字母小寫,且使用首字母大寫的形式分割單詞
-
▪ 成員變量使用“_”作爲前綴(如:“NSString *_varName;”。雖然這與蘋果的標準(使
用“_”作爲後綴)相沖突,但基於以下原因,仍使用“_”作爲前綴。
▪ 使用“_”作爲前綴,更容易在有代碼自動補全功能的IDE中區分“屬性(self.userInfo)”和“成員變量(_userInfo)”
-
▪ 常量(#define, enums, const等)使用小寫“k”作爲前綴,首字母大寫來分割單詞。如:
kInvalidHandle
•註釋
◦ 待完善• Cocoa 和 Objective-C特有的規則
-
成員變量使用@private。如:
@interface MyClass : NSObject { @private
id _myInstanceVariable; }
// public accessors, setter takes ownership - (id)myInstanceVariable; - (void)setMyInstanceVariable:(id)theVar; @end
-
Indentify Designated Initializer▪ 待完善
-
Override Desingated Initializer
▪ 待完善◦ 初始化
▪ 在初始化方法中,不要將變量初始化爲“0”或“nil”,那是多餘的
▪ 內存中所有的新創建的對象(isa除外)都是0,所以不需要重複初始化爲“0”或“nil”◦ 避免顯式的調用+new方法
▪ 禁止直接調用NSObject的類方法+new,也不要在子類中重載它。使用alloc和init方法◦ 保持公共API的簡潔性
▪
待完善
◦ #import VS #include
▪ 使用#import引入Ojbective-C和Ojbective-C++頭文件,使用#include引入C和C++頭文件
◦ import根框架(root
frameworks),而非各單個文件
▪ 雖然有時我們僅需要框架(如Cocoa
或 Foundation)的某幾個頭文件,但引入根文件編譯
器會運行的更快。因爲根框架(root frameworks)一般會預編譯,所以加載會更快。再次強調:使用
#import 而非
#include
來引入Objective-C框架。如:
#import <Foundation/NSArray.h> //
禁止
#import <Foundation/NSString.h>
...
#import <Foundation/Foundation.h> // 對頭◦ 創建對象時儘量使用autorelease
-
▪ 創建臨時對象時,儘量同時在同一行中 autorelease 掉,而非使用單獨的 release 語句
-
▪ 雖然這樣會稍微有點慢,但這樣可以阻止因爲提前 return 或其他意外情況導致的內存泄露。
通盤來看這是值得的。如:
// 避免這樣使用(除非有性能的考慮)
MyController* controller = [[MyController alloc] init];
// ... 這裏的代碼可能會提前return ...
[controller release];
// 這樣更好
MyController* controller = [[[MyController alloc] init] autorelease];◦ 先autorelease,再retain
-
▪ 在爲對象賦值時,遵從“先autorelease,再retain”
-
▪ 在將一個新創建的對象賦給變量時,要先將舊對象release掉,否則會內存泄露。市面上有很
多方法來handle這種情況,這裏選擇“先autorelease,再retain”的方法,這種方法不易引入error。注意:在循環中這種方法會“填滿”autorelease pool,稍稍影響效率,但是Google和我( :P )認爲這個代價是可以接受的。如:
- (void)setFoo:(GMFoo *)aFoo {[foo_ autorelease]; // 如果foo_和aFoo是同一個對象(foo_ == aFoo),dealloc不會被調用
foo_ = [aFoo retain]; }
◦ dealloc的順序要與變量聲明的順序相同
▪ 這有利於review代碼
▪ 如果dealloc中調用其他方法來release變量,將被release的變量以註釋的形式標註清楚◦ NSString的屬性的setter使用“copy”
▪ 禁止使用retain,以防止意外的修改了NSString變量的值。如:
- (void)setFoo:(NSString *)aFoo {
[foo_ autorelease];
foo_ = [aFoo copy];
}
或
@property (nonatomic, copy) NSString *aString;
◦ 避免拋出異常(Throwing Exceptions)▪ 待完善
◦ 對
nil
的檢查
▪ 僅在有業務邏輯需求時檢查nil,而非爲了防止崩潰
▪ 向 nil 發送消息不會導致系統崩潰,Objective-C運行時負責處理。◦ BOOL陷阱
-
▪ 將int值轉換爲BOOL時應特別小心。避免直接和YES比較
-
▪ Objective-C中,BOOL被定義爲unsigned char,這意味着除了 YES(1) 和NO(0)外它
還可以是其他值。禁止將int直接轉換(cast or convert)爲BOOL。
-
▪ 常見的錯誤包括:將數組的大小、指針值或位運算符的結果轉換(cast or convert)爲
BOOL,因爲該BOOL值的結果取決於整型值的最後一位
-
▪ 將整型值轉換爲BOOL的方法:使用三元運算符返回YES / NO,或使用位運算符(&&,||,!)
-
▪ BOOL、_Bool和bool之間的轉換是安全的,但是BOOL和Boolean間的轉換不是安全的,所以
將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)...
◦ 屬性
▪ 命名:與去掉“_”前綴的成員變量相同,使用@synthesize將二者聯繫起來。如:
// abcd.h
@interface MyClass : NSObject {
@private
NSString *_name;
}
@property (copy, nonatomic) NSString *name;
@end
// abcd.m
@implementation MyClass
@synthesize name = _name;
@end
▪ 位置:屬性的聲明緊隨成員變量塊之後,中間空一行,無縮進。如上例所示▪
嚴把權限:對不需要外部修改的屬性使用readonly
▪
NSString使用copy而非retain
▪
CFType使用@dynamic,
禁止使用@synthesize
▪ 除非必須,使用nonatomic• Cocoa Pattern
◦ Delegate Pattern(委託)
-
▪ delegate對象使用assign,禁止使用retain。因爲retain會導致循環索引導致內存泄露,
並且此類型的內存泄露無法被Instrument發現,極難調試
-
▪ 成員變量命名爲_delegate,屬性名爲delegate
◦ Model/View/Controller▪ Model和View分離
▪ 不多解釋
▪ Controller獨立於View和Controller▪ 不要在與view相關的類中添加過多的業務邏輯代碼,這讓代碼的可重用性很差
▪ Controller負責業務邏輯代碼,且Controller的代碼與view儘量無關
▪ 使用@protocal 定義回調APIs,如果並非所有方法都是必須的,使用@optional標示•其他
◦ init方法和dealloc方法是是最常用的方法,所以將他們放在類實現的開始位置◦ 使用空格將相同的變量、屬性對齊,使用換行分組