本文參考Apple & Google Objective-C編碼規范,根據個人的編碼習慣,總結出一些通用的編碼規則。
代碼示例
頭文件示例代碼
下面是用Objective-C語言編寫的規范的頭文件示例代碼。
// // BTFoo.h // CodingGuidelines // // Created by Tracy E on 12-8-13. // Copyright (c) 2012年 ChinaMWorld Inc. All rights reserved. // #import <Foundation/Foundation.h> /** A sample class demonstrating good Objective-C style. All interfaces, categories, and protocols (read: all top-level declarations in a header) MUST be commented. Comments must alse be adjacent to the object they're documenting. */ @protocol BTFooDelegate; @interface BTFoo : NSObject{ @private NSString *_bar; CGFloat _price; @public NSString *_name; id<BTFooDelegate> _delegate; } @property (nonatomic, copy) NSString *name; //the name of Foo. default is nil. @property (nonatomic, assign) id<BTFooDelegate> delegate; //weak reference. default is nil. /** initializer. |string| will be copied and assigned to |_name|. @param string The foo name. @return an autorelease instance of BTFoo. */ - (id)initWithString:(NSString *)string; /** Designated initailizer. initialize a new BTFoo object. @param name The model name. @param number The model number. @param price The model price. @return a newly initialized object. */ - (id)initFooWithModelName:(NSString *)name modelNumber:(NSUInteger)number modelPrice:(CGFloat)price; /** Dosomething... @param name The model name. @param number The model number. @param price The model price. */ - (void)doName:(NSString *)name modelNumber:(NSUInteger)number modelPrice:(CGFloat)price; //Gets and Sets |_bar|. - (NSString *)bar; - (void)setBar:(NSString *)bar; @end
源文件示例代碼
下面是用Objective-C語言編寫的規范的源文件示例代碼。
// // BTFoo.m // CodingGuidelines // // Created by Tracy E on 12-8-13. // Copyright (c) 2012年 ChinaMWorld Inc. All rights reserved. // #import "BTFoo.h" @interface BTFoo (PrivateMethods) + (id)fooWithString:(NSString *)string; @end @implementation BTFoo @synthesize name = _name; @synthesize delegate = _delegate; - (void)dealloc{ [_bar release]; [_name release]; [super dealloc]; } - (id)initWithString:(NSString *)string{ self = [super init]; if (self) { _name = [string copy]; _bar = [[NSString alloc] initWithFormat:@"bar"]; } return self; } - (id)initFooWithModelName:(NSString *)name modelNumber:(NSUInteger)number modelPrice:(CGFloat)price{ self = [BTFoo fooWithString:name]; if (self) { _price = price; } return self; } - (void)doName:(NSString *)name modelNumber:(NSUInteger)number modelPrice:(CGFloat)price{ } - (NSString *)bar{ return _bar; } - (void)setBar:(NSString *)bar{ [_bar autorelease]; _bar = [bar copy]; } #pragma mark BTFoo Private Methods + (id)fooWithString:(NSString *)string{ return [[[BTFoo alloc] initWithString:string] autorelease]; } - (void)doSomethingWith:(BTFoo *)theFoo rect:(CGRect)theRect interval:(float)theInterval{ //... } - (void)short:(BTFoo *)theFoo longKeyword:(CGRect)theRect evenLongerKeyword:(float)theInterval{ //... } @end
間距與格式
程序中代碼的排版,縮進,間隔等可以根據IDE的具體設置而決定,但最終都應該使代碼的間距與格式統一,達到整齊美觀的效果。
指針的位置
類型與“*”之間一個空格,“*”與變量名之間沒有空格。
NSString *_text;
每行代碼的長度
每行代碼的長度不超過100個字符。每行代碼的字符數可通過IDE進行設置。(設置:XCode —> Preferences —> Text Editing —> Page guide at column : 100)
方法的聲明與定義
聲明方法時,在 - 或 + 與返回類型之間應該留一個空格的間距。參數表的參數之間不要留間隔。
星號(*)前的空格是必須的。
- (id)initWithString:(NSString *)string;
如果參數過多,每個參數應各占一行。在有多行參數的情況下,每行參數前的冒號應對齊。
- (void)doSomethingWith:(BTFoo *)theFoo rect:(CGRect)theRect interval:(float)theInterval{ //... }
當第一行的函數關鍵字比其后面行的關鍵字短時,后面的行應縮進四個空格。保證后續的關鍵字垂直對齊,而不應該采用冒號對齊的方式。
- (void)short:(BTFoo *)theFoo longKeyword:(CGRect)theRect evenLongerKeyword:(float)theInterval{ //... }
方法的調用
如果調用的方法沒有超出一行(100字符長),則所有參數在同一行。
[item1 setTitle:@"提交" forState:UIControlStateNormal];
如果調用的方法過長,則每個參數占用一行,以冒號對其。
[button addTarget:self
action:@selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
如果調用的方法過長,但方法名比參數名短,每個參數一行,縮進四個空格豎直對齊。
[self short:myFoo longKeyword:rect eventLongerKeyword:10];
@public 與 @private的使用
使用權限控制符@public 和@private 應縮進兩個空格。
@interface MyClass : NSObject{ @private NSInteger _count; @public NSString *_title; } @end
協議的使用
在類型標識符與協議的名之間不應該有空格。此協議使用的規范適用於類的聲明、成員變量的聲明以及方法的聲明
@protocol MyClassDelegate; @interface MyClass : NSObject{ @private id<MyClassDelegate> _delegate; } @property (nonatomic, assign) id<MyClassDelegate> delegate;
如果申明中包含多個protocal且超出一行時換行,縮進兩個空格。
@interface CustomViewController : UIViewController<UITableViewDataSource, UITableViewDataSource, UITextFieldDelegate, UISearchBarDelegate>{ }
@property,@synthesize,@dynamic的使用
@property與左括號之間留一個空格。
@property和@synthesize的縮進級別與@interface或者@implementation的縮進級別相同。
@property的聲明語句應該緊跟在類的成員變量聲明語句塊的后面。
@synthesize的實現語句應該緊跟在@implementation語句之后。
@interface BTAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end @implementation BTAppDelegate @synthesize window = _window;
命名規范
文件的命名
文件的名字應該反映其中包含的類名字,也應該遵循項目的風格習慣。
文件擴展命的使用規范如下:
.h | C/C++/Objective-C頭文件 |
.m | Objective-C源文件 |
.mm | Objective-C++源文件 |
.cc | 純C++源文件 |
.c | C源文件 |
類的命名
類名應該用大寫開頭的駝峰命名法。
MyTableView、HomeViewController
在應用程序級別的代碼中,盡量不要使用帶前綴的類名。每個類都有相同的前綴不能提高可讀性。如果是編寫多個應用程序間的共用代碼,那么需要為類名加上前綴。
Category的命名
Category的命名應該包含2-3個字符的前綴,用於說明Category是屬於具體的某個工程的。
當聲明一個Category時,Category的左括號與類名之間應該留一個空格的間隔。
例如要實現NSString的一個Category,用於實現解析功能。Category的文件名應該命名為NSString+GTMParsing.h,而Category的名字為GTMStringParsingAdditions,Category的名字與文件名不一致的原因是,在NSString+GTMParsing.h的文件中,可以聲明多個用於解析功能的NSString類的Category。
Objective-C方法命名
1.方法應使用小寫開頭的駝峰法命名,每個參數都應該小寫開頭。
2.方法名應該盡可能讀起來像一句話,參數名就如同方法名的補充說明(比如convertPoing:fromRect: 或者 replaceCharactersInRange:withString: )。
3.方法明中要避免單詞縮寫。
- (void)setBGImage:(UIImage *)img; //避免 - (void)setBackgroundImage:(UIImage *)image; //推薦
變量的命名
變量名應使用小寫開頭的駝峰法命名。
類成員變量名應該以一個下划線開始。
常量(預定義,枚舉,局部常量等)使用小寫k開頭的駝峰法。例如:
localVariable; //局部變量 _instanceVariable; //成員變量 kConstant; //常量
注釋
文件的注釋
每個文件的開頭都應該包含以下的注釋。
1.文件名。
2.項目名稱。
3.文件的創建者。
4.創建日期。
5.版權說明。
6.必要時還應包含許可聲明。(如:Apache 2.0, BSD, LGPL, GPL)
聲明的注釋
對每個接口,類別,協議進行聲明時,都應該有用於解釋其功能或者如何使用的注釋。
每個方法/函數聲明時,都應該有用於解釋其功能,參數值,返回值的注釋,必要時還應該說明方法/函數的使用注意事項。
當類的成員變量可用於多線程訪問時,應該對其使用做出詳細的說明和解釋。
//A delegate for NSApplication to handle notifications about app //launch and shut down. Owned by the main app controller. @interface AyAppDelegate : NSObject{ }
@end
實現的注釋
在為接口,類別,協議,方法/函數等的實現寫注釋時,應該使用豎線引用變量,函數名或者其他符號。
//Sometimes we need |count| to be less than zero. //Remember to call |StringWithSpaces("foo bar baz")|
屬性的類型
應該嚴格的控制屬性的類型(readonly, copy, retain, assign)
不允許外部修改的屬性,使用readonly;
NSString類型使用copy而不是retain;
代理delegate使用assign,禁止使用retain。
注意事項
成員變量訪問權限
成員變量應該盡可能地定義為@private。
重寫指定初始化方法
當對一個類進行子類化時,一定要重寫父類的指定初始化方法。如果沒有正確重寫父類的指定初始化方法,子類的初始化方法可能不會被調用,這會導致很多微妙而難以預測的錯誤。
初始化
沒有必要在類的初始化方法中將成員變量的初始值設置為0或者nil。
//都是多余的 BOOL editable = NO; NSInteger currentIndex = 0; NSString *title = nil;
BOOL的使用
1.當將一個整型賦值給BOOL類型時應該特別注意,因為BOOL的類型為unsigned char。
2.不應該將BOOL類型的變量直接與YES進行比較
if(editable){/*推薦*/ } if(editable == YES){/*不推薦*/}