總體命名規(guī)則
- 命名原則首先是要顧名思義。命名不要太隨意,描述性的命名是最好的。
- 變量名、方法名遵守駝峰命名法,首字母小寫。
- 類名、協(xié)議名、枚舉類型遵守駝峰命名法,首字母大寫,這些命名前面均需加前綴,推薦“JM“ + (功能簡稱)。
- 常量名以k開頭,如kJMTest。
- 宏所有字母均大寫,命名前面加前綴,推薦”JM“ + (功能簡稱)。
- 通知Notification的格式 推薦 類/頭文件名 + 進行狀態(tài)(Will | Did) + 通知名稱 + Notification
- 協(xié)議名使用Delegate做后綴,DataSource使用DataSource做后綴。
頭文件
聲明一個孤立的class或protocol 將聲明放入單獨的文件,
使頭文件名與聲明的class/protocol相同。聲明關(guān)聯(lián)的class或protocol 將關(guān)聯(lián)的聲明(class/category/protocol)放入同一個頭文件,頭文件名與主要的class/category/protocol相同。
變量
變量盡量以描述性的方式來命名。單個字符的變量命名應(yīng)該盡量避免,除了在for()循環(huán)。
星號表示變量是指針。例如, <font color=#FF69B4>NSString *text
</font>既不是 <font color=#FF69B4>NSString* text
</font> 也不是 <font color=#FF69B4>NSString * text
</font>,除了一些特殊情況下常量。
-
類成員變量
類中所有成員變量以屬性的方式提供,不要使用其他類型的變量聲明。
通過使用'back'屬性(_variable,變量名前面有下劃線)直接訪問實例變量應(yīng)該盡量避免,除了在初始化方法 <font color=#FF69B4>(init, initWithCoder:</font>, 等…), <font color=#FF69B4>dealloc</font> 方法和自定義的<font color=#FF69B4>setters</font>和<font color=#FF69B4>getters</font>。如果要使用成員變量,必須以下劃線'_'開頭,如 NSString *_name。局部變量不應(yīng)該包含下劃線。應(yīng)該:
@interface Test : NSObject @property (nonatomic, strong) NSString *name; @end
不應(yīng)該:
@interface Test : NSObject { NSString *_name; }
私有屬性應(yīng)該聲明在類的.m中,只有需要外部使用的變量才聲明在.h中。
-
所有屬性特性應(yīng)該顯式地列出來,有助于新手閱讀代碼。屬性特性的順序應(yīng)該是atomicity、storage。
應(yīng)該:
@property (nonatomic, strong) NSString *name;
不應(yīng)該:
@property (nonatomic) NSString *testName;
屬性是指針類型的集合時,格式如下:
@property (nonatomic, strong) NSArray <Item *>*array;
屬性是delegate時,聲明成weak,防止循環(huán)引用,格式如下:
@property(nonatomic, weak) id<UIScrollViewDelegate> delegate;
常量
常量應(yīng)該使用static來聲明而不是使用#define,除非顯式地使用宏。
應(yīng)該:
static NSString * const kJMAboutViewController = @"JMAboutViewController";
static CGFloat const kRowHeight = 50.0;
不應(yīng)該:
#define kJMAboutViewController @"JMAboutViewController"
#define kRowHeight 2
布爾值
Objective-C使用的是BOOL值,對應(yīng)的是YES和NO。true和false是bool類型,Objective-C不要使用。
既然nil解析成NO,所以沒有必要在條件語句比較。不要拿某樣?xùn)|西直接與YES比較。
應(yīng)該:
if (someObject) {
}
if (![anotherObject boolValue]) {
}
不應(yīng)該:
if (someObject == nil) {}
if ([anotherObject boolValue] == NO) {}
if (isAwesome == YES) {} // Never do this.
if (isAwesome == true) {} // Never do this.
如果BOOL屬性的名字是一個形容詞,屬性就能忽略"is"前綴,但要指定get訪問器的慣用名稱。例如:
@property (assign, nonatomic, getter=isEditable) BOOL editable;
枚舉型
普通枚舉型
typedef NS_ENUM(NSInteger,JMTypeTest){
kJMTypeA = 0, // 注釋
kJMTypeB = 1, // 注釋
kJMTypeC = 2, // 注釋
kJMTypeD = 3 // 注釋
};
可按位或
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
字面值
NSString, NSDictionary, NSArray, 和 NSNumber的字面值應(yīng)該在創(chuàng)建這些類的不可變實例時被使用。請?zhí)貏e注意nil值不能傳入NSArray和NSDictionary字面值,因為這樣會導(dǎo)致crash。
應(yīng)該:
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingStreetNumber = @10018;
不應(yīng)該:
NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingStreetNumber = [NSNumber numberWithInteger:10018];
操作符
一元操作符不帶空格,多元運算符要帶空格隔開。
-
逗號后面都要跟隨一個空格。
NSArray *array = @[1, 2, 3, 4];
-
二元操作符,如+, -, *, /,>, <, =, ==, ->, <<, >>等。
a + b = c; a > b; a == b; a << 2; Object -> c;
-
三元操作符 Non-boolean的變量與某東西比較,加上括號()會提高可讀性。如果被比較的變量是boolean類型,那么就不需要括號。
應(yīng)該:
NSInteger value = 5; result = (value != 0) ? x : y; BOOL isHorizontal = YES; result = isHorizontal ? x : y;
不應(yīng)該:
result = a > b ? x = c > d ? c : d : y; result = a ?: b;
集合類型
- 如果初始值太長,元素需要換行,使?四個空格來進行縮進,右括號 ] 或者 } 寫在新的?行,并且與調(diào)?語法糖那?代碼的第一個非空字符對齊。
- 構(gòu)造字典時,字典的 Key 和 Value與中間的冒號都要留一個空格。
- 需要使用類似”增刪改查”方法來對集合進行操作時,方法名前面加上“add”、“remove”、“update”類似表明函數(shù)功能的關(guān)鍵字。
NSArray *array = @[
@"This",
@"is",
@"an",
@"array"
];
NSDictionary *dictionary = @{
NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
NSForegroundColorAttributeName : fontColor
};
系統(tǒng)保留字
- 系統(tǒng)保留字如if/else、do/while、try/catch 跟()和{}之間都要留一個空格。
- 將關(guān)鍵字與花括號放在一行。
- switch語句每個分支都必須用大括號包起來。
- switch使用枚舉型時,如果窮舉完所有情況,不能有default分支。其他情況,都必須有default分支。
應(yīng)該
if (a == 1) {
NSLog(@"test1");
} else if (b == 2) {
NSLog(@"test2");
} else {
NSLog(@"test3");
}
switch (condition) {
case 1:
// ...
break;
case 2: {
// ...
// Multi-line example using braces
}
break;
case 3:
// ...
break;
default:
// ...
break;
}
不應(yīng)該
if(a==1){
NSLog(@"test1");
}else if(b==2){
NSLog(@"test2");
}else{
NSLog(@"test3");
}
if條件語句
-
條件語句主體為了防止出錯應(yīng)該使用大括號包圍,即使只有一行代碼。這些錯誤包括添加第二行代碼和期望它成為if語句,但是沒包含進大括號;還有,更危險的可能發(fā)生在if語句里面一行代碼被注釋了,然后下一行代碼不知不覺地成為if語句的一部分。
應(yīng)該:
if (!error) { return success; }
不應(yīng)該:
if (!error) return success;
或
if (!error) return success;
-
不要使用過多的分支,善于使用return來提前返回錯誤情況,把最正確的情況放到最后返回。
應(yīng)該
if (!user.UserName) { return NO; } if (!user.Password) { return NO; } if (!user.Email) { return NO; } return YES;
不應(yīng)該
BOOL isValid = NO; if (user.UserName) { if (user.Password) { if (user.Email) { isValid = YES; } } } return isValid;
-
條件過多,過長的時候應(yīng)該換行。條件表達式如果很長,則需要將他們提取出來賦給一個BOOL值,或者抽取出一個方法。
應(yīng)該
if (condition1 && condition2 && condition3 && condition4) { // Do something }
BOOL finalCondition = condition1 && condition2 && condition3 && condition4 if (finalCondition) { // Do something }
if ([self canDelete]) { // Do something } - (BOOL)canDelete{ BOOL finalCondition1 = condition1 && condition2; BOOL finalCondition2 = condition3 && condition4; return condition1 && condition2; }
不應(yīng)該
if (condition1 && condition2 && condition3 && condition4) { // Do something }
if條件語句是和常量比較時,多于3個,使用switch/case實現(xiàn)。
函數(shù)聲明
- 方法名和參數(shù)盡量讀起來像是一句話。
- 方法名不允許使用 get、 do 或does 做前綴,動詞本身的暗示就夠了。
- 如果方法是為了獲取對象的一個屬性值,直接用屬性名稱來命名方法,不要添加 get 或其他的動詞。
- and 和 with 不應(yīng)該用于多個參數(shù)來說明。
- 方法類型(-/+)和返回值之間要有一個空格。
- 參數(shù)類型和指針符之間要留空格。
- 參數(shù)類型和冒號之間不需要留空格。
- 參數(shù)類型和參數(shù)名之間不需要留空格。
應(yīng)該
- (UIView *)initWithTitle:(NSString *)title backgroundColor:(UIColor *)color;
不應(yīng)該
-(UIView *)initWithTitle:(NSString *)title withBackgroundColor: (UIColor*) color;
函數(shù)實現(xiàn)
- { 和函數(shù)名可以在同一行,也可以換行。但是一個類文件里面要保持統(tǒng)一風(fēng)格。修改者要遵循創(chuàng)建者的風(fēng)格。
- 函數(shù)和函數(shù)之間空一行。
- 內(nèi)部實現(xiàn)時,花括號的嵌套要注意對齊。也可以全部選中,然后使用快捷鍵control+I。
- 每行建議不超過120個字符,函數(shù)名過長時,使用冒號對齊的方式。
- 如果在不同的函數(shù)內(nèi)部有相同的功能,應(yīng)該把相同的功能抽取出來單獨作為另一個函數(shù)。
- 將函數(shù)內(nèi)部比較復(fù)雜的邏輯提取出來作為單獨的函數(shù)。
- 盡量避免空方法的產(chǎn)生。
- (void)popBack {
[self.navigationController popViewControllerAnimated:YES];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
.m文件整理
- 如果有實例化函數(shù)應(yīng)該放在最前面。
- 如果是view或者viewController的.m文件,應(yīng)該按照loadView、viewDidLoad、viewWillApperar、viewDidAppear、viewWillDisappear、viewDidDisapper和dealloc的順序?qū)崿F(xiàn),并且這些生命周期相關(guān)的函數(shù)放在最前面。
- 后面再跟viewWillLayoutSubviews和viewDidLayoutSubviews等這些布局相關(guān)的函數(shù)。
- setter、getter同類型方法放在一起,并用pragma mark - setter方法 或 pragma mark - getter方法進行標(biāo)注。
- 相同delegate和datasource的函數(shù)放在一起,并用pragma mark - xxx標(biāo)注。
init方法
Init方法應(yīng)該遵循Apple生成代碼模板的命名規(guī)則。返回類型應(yīng)該使用instancetype而不是id。
- (instancetype)init {
self = [super init];
if (self) {
// ...
}
return self;
}
類構(gòu)造方法
當(dāng)類構(gòu)造方法被使用時,它應(yīng)該返回類型是instancetype而不是id。這樣確保編譯器正確地推斷結(jié)果類型。
@interface Airplane
+ (instancetype)airplaneWithType:(RWTAirplaneType)type;
@end
回調(diào)方法
函數(shù)調(diào)用的可知性,回調(diào)時被調(diào)用者要知道其調(diào)用者,方便信息的傳遞,所以建議在回調(diào)方法第一個參數(shù)中加上調(diào)用者。除非只有一個名為sender的參數(shù)。
如:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)windowShouldClose:(id)sender;
CGRect函數(shù)
當(dāng)訪問CGRect里的x, y, width, 或 height時,應(yīng)該使用CGGeometry函數(shù)而不是直接通過結(jié)構(gòu)體來訪問。引用Apple的CGGeometry:
應(yīng)該:
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
CGRect frame = CGRectMake(0.0, 0.0, width, height);
不應(yīng)該:
CGRect frame = self.view.frame;
CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;
CGRect frame = (CGRect){ .origin = CGPointZero, .size = frame.size };
單例模式
單例對象應(yīng)該使用線程安全模式來創(chuàng)建共享實例。
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Block
- 較短的Block可以寫在一行內(nèi)。
- 如果block過于龐大,應(yīng)該使用typedef單獨聲明成一個變量來使用。
typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
- 如果分行顯示的話,block的右括號應(yīng)該和調(diào)用block那行代碼的第一個非空字符對齊。
- block內(nèi)的代碼注意縮進對齊。
- ^ 和左括號 ( 或者 { 之間沒有空格,參數(shù)列表的右括號 ) 和 {之間有一個空格。
__weak typeof(manager)wManager = manager;
[manager POST:url parameters:reqDic progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[wManager invalidateSessionCancelingTasks:false];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[wManager invalidateSessionCancelingTasks:false];
}];
圖片資源命名
圖片資源命名方式,以 模塊 + 功能 為組織形式,如果相同功能有多個,比如表情,則再加編號。
如:
tabbar_item_1.png
tabbar_item_2.png
maitoutiao_topicon_1.png
maitoutiao_topicon_2.png
注釋
- 使用 // 注釋時,后面要加一個空格,如果注釋+被注釋文本過長,使用/*xxx*/。
- 對函數(shù)注釋時,將光標(biāo)移到函數(shù)行,使用option+command+/快捷鍵來生成注釋。
- 對delegate和dataSource實現(xiàn)時,在第一個函數(shù)前面#pragma mark - xxx來進行標(biāo)注。
警告??
盡量減少??的產(chǎn)生,能修改的要及時修改。