總體命名規(guī)則
- 命名原則首先是要顧名思義。命名不要太隨意,描述性的命名是最好的健民。
- 變量名抒巢、方法名遵守駝峰命名法,首字母小寫秉犹。
- 類名蛉谜、協(xié)議名、枚舉類型遵守駝峰命名法凤优,首字母大寫悦陋,這些命名前面均需加前綴,推薦“JM“ + (功能簡稱)筑辨。
- 常量名以k開頭,如kJMTest幸逆。
- 宏所有字母均大寫棍辕,命名前面加前綴,推薦”JM“ + (功能簡稱)还绘。
- 通知Notification的格式 推薦 類/頭文件名 + 進行狀態(tài)(Will | Did) + 通知名稱 + Notification
- 協(xié)議名使用Delegate做后綴楚昭,DataSource使用DataSource做后綴。
頭文件
聲明一個孤立的class或protocol 將聲明放入單獨的文件拍顷,
使頭文件名與聲明的class/protocol相同抚太。聲明關聯(lián)的class或protocol 將關聯(lián)的聲明(class/category/protocol)放入同一個頭文件,頭文件名與主要的class/category/protocol相同。
變量
變量盡量以描述性的方式來命名尿贫。單個字符的變量命名應該盡量避免电媳,除了在for()循環(huán)。
星號表示變量是指針庆亡。例如匾乓, <font color=#FF69B4>NSString *text
</font>既不是 <font color=#FF69B4>NSString* text
</font> 也不是 <font color=#FF69B4>NSString * text
</font>,除了一些特殊情況下常量又谋。
-
類成員變量
類中所有成員變量以屬性的方式提供拼缝,不要使用其他類型的變量聲明。
通過使用'back'屬性(_variable彰亥,變量名前面有下劃線)直接訪問實例變量應該盡量避免咧七,除了在初始化方法 <font color=#FF69B4>(init, initWithCoder:</font>, 等…), <font color=#FF69B4>dealloc</font> 方法和自定義的<font color=#FF69B4>setters</font>和<font color=#FF69B4>getters</font>任斋。如果要使用成員變量继阻,必須以下劃線'_'開頭,如 NSString *_name。局部變量不應該包含下劃線仁卷。應該:
@interface Test : NSObject @property (nonatomic, strong) NSString *name; @end
不應該:
@interface Test : NSObject { NSString *_name; }
私有屬性應該聲明在類的.m中穴翩,只有需要外部使用的變量才聲明在.h中。
-
所有屬性特性應該顯式地列出來锦积,有助于新手閱讀代碼芒帕。屬性特性的順序應該是atomicity、storage丰介。
應該:
@property (nonatomic, strong) NSString *name;
不應該:
@property (nonatomic) NSString *testName;
屬性是指針類型的集合時背蟆,格式如下:
@property (nonatomic, strong) NSArray <Item *>*array;
屬性是delegate時,聲明成weak哮幢,防止循環(huán)引用带膀,格式如下:
@property(nonatomic, weak) id<UIScrollViewDelegate> delegate;
常量
常量應該使用static來聲明而不是使用#define,除非顯式地使用宏橙垢。
應該:
static NSString * const kJMAboutViewController = @"JMAboutViewController";
static CGFloat const kRowHeight = 50.0;
不應該:
#define kJMAboutViewController @"JMAboutViewController"
#define kRowHeight 2
布爾值
Objective-C使用的是BOOL值垛叨,對應的是YES和NO。true和false是bool類型柜某,Objective-C不要使用嗽元。
既然nil解析成NO,所以沒有必要在條件語句比較喂击。不要拿某樣東西直接與YES比較剂癌。
應該:
if (someObject) {
}
if (![anotherObject boolValue]) {
}
不應該:
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的字面值應該在創(chuàng)建這些類的不可變實例時被使用旁壮。請?zhí)貏e注意nil值不能傳入NSArray和NSDictionary字面值,因為這樣會導致crash谐檀。
應該:
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingStreetNumber = @10018;
不應該:
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類型棍郎,那么就不需要括號其障。
應該:
NSInteger value = 5; result = (value != 0) ? x : y; BOOL isHorizontal = YES; result = isHorizontal ? x : y;
不應該:
result = a > b ? x = c > d ? c : d : y; result = a ?: b;
集合類型
- 如果初始值太長,元素需要換行涂佃,使?四個空格來進行縮進,右括號 ] 或者 } 寫在新的?行,并且與調?語法糖那?代碼的第一個非空字符對齊励翼。
- 構造字典時,字典的 Key 和 Value與中間的冒號都要留一個空格辜荠。
- 需要使用類似”增刪改查”方法來對集合進行操作時汽抚,方法名前面加上“add”、“remove”伯病、“update”類似表明函數(shù)功能的關鍵字造烁。
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 跟()和{}之間都要留一個空格膨蛮。
- 將關鍵字與花括號放在一行。
- switch語句每個分支都必須用大括號包起來季研。
- switch使用枚舉型時,如果窮舉完所有情況誉察,不能有default分支与涡。其他情況,都必須有default分支。
應該
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;
}
不應該
if(a==1){
NSLog(@"test1");
}else if(b==2){
NSLog(@"test2");
}else{
NSLog(@"test3");
}
if條件語句
-
條件語句主體為了防止出錯應該使用大括號包圍驼卖,即使只有一行代碼氨肌。這些錯誤包括添加第二行代碼和期望它成為if語句,但是沒包含進大括號酌畜;還有怎囚,更危險的可能發(fā)生在if語句里面一行代碼被注釋了,然后下一行代碼不知不覺地成為if語句的一部分桥胞。
應該:
if (!error) { return success; }
不應該:
if (!error) return success;
或
if (!error) return success;
-
不要使用過多的分支恳守,善于使用return來提前返回錯誤情況,把最正確的情況放到最后返回贩虾。
應該
if (!user.UserName) { return NO; } if (!user.Password) { return NO; } if (!user.Email) { return NO; } return YES;
不應該
BOOL isValid = NO; if (user.UserName) { if (user.Password) { if (user.Email) { isValid = YES; } } } return isValid;
-
條件過多催烘,過長的時候應該換行。條件表達式如果很長缎罢,則需要將他們提取出來賦給一個BOOL值伊群,或者抽取出一個方法。
應該
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; }
不應該
if (condition1 && condition2 && condition3 && condition4) { // Do something }
if條件語句是和常量比較時策精,多于3個舰始,使用switch/case實現(xiàn)。
函數(shù)聲明
- 方法名和參數(shù)盡量讀起來像是一句話咽袜。
- 方法名不允許使用 get丸卷、 do 或does 做前綴,動詞本身的暗示就夠了酬蹋。
- 如果方法是為了獲取對象的一個屬性值及老,直接用屬性名稱來命名方法,不要添加 get 或其他的動詞范抓。
- and 和 with 不應該用于多個參數(shù)來說明骄恶。
- 方法類型(-/+)和返回值之間要有一個空格。
- 參數(shù)類型和指針符之間要留空格匕垫。
- 參數(shù)類型和冒號之間不需要留空格僧鲁。
- 參數(shù)類型和參數(shù)名之間不需要留空格。
應該
- (UIView *)initWithTitle:(NSString *)title backgroundColor:(UIColor *)color;
不應該
-(UIView *)initWithTitle:(NSString *)title withBackgroundColor: (UIColor*) color;
函數(shù)實現(xiàn)
- { 和函數(shù)名可以在同一行象泵,也可以換行寞秃。但是一個類文件里面要保持統(tǒng)一風格。修改者要遵循創(chuàng)建者的風格偶惠。
- 函數(shù)和函數(shù)之間空一行春寿。
- 內部實現(xiàn)時,花括號的嵌套要注意對齊忽孽。也可以全部選中绑改,然后使用快捷鍵control+I谢床。
- 每行建議不超過120個字符,函數(shù)名過長時厘线,使用冒號對齊的方式识腿。
- 如果在不同的函數(shù)內部有相同的功能,應該把相同的功能抽取出來單獨作為另一個函數(shù)造壮。
- 將函數(shù)內部比較復雜的邏輯提取出來作為單獨的函數(shù)渡讼。
- 盡量避免空方法的產生。
- (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ù)應該放在最前面耳璧。
- 如果是view或者viewController的.m文件成箫,應該按照loadView、viewDidLoad楞抡、viewWillApperar伟众、viewDidAppear、viewWillDisappear召廷、viewDidDisapper和dealloc的順序實現(xiàn)凳厢,并且這些生命周期相關的函數(shù)放在最前面。
- 后面再跟viewWillLayoutSubviews和viewDidLayoutSubviews等這些布局相關的函數(shù)竞慢。
- setter先紫、getter同類型方法放在一起,并用pragma mark - setter方法 或 pragma mark - getter方法進行標注筹煮。
- 相同delegate和datasource的函數(shù)放在一起遮精,并用pragma mark - xxx標注。
init方法
Init方法應該遵循Apple生成代碼模板的命名規(guī)則败潦。返回類型應該使用instancetype而不是id本冲。
- (instancetype)init {
self = [super init];
if (self) {
// ...
}
return self;
}
類構造方法
當類構造方法被使用時,它應該返回類型是instancetype而不是id劫扒。這樣確保編譯器正確地推斷結果類型檬洞。
@interface Airplane
+ (instancetype)airplaneWithType:(RWTAirplaneType)type;
@end
回調方法
函數(shù)調用的可知性,回調時被調用者要知道其調用者沟饥,方便信息的傳遞添怔,所以建議在回調方法第一個參數(shù)中加上調用者。除非只有一個名為sender的參數(shù)贤旷。
如:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)windowShouldClose:(id)sender;
CGRect函數(shù)
當訪問CGRect里的x, y, width, 或 height時广料,應該使用CGGeometry函數(shù)而不是直接通過結構體來訪問。引用Apple的CGGeometry:
應該:
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);
不應該:
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 };
單例模式
單例對象應該使用線程安全模式來創(chuàng)建共享實例幼驶。
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Block
- 較短的Block可以寫在一行內艾杏。
- 如果block過于龐大,應該使用typedef單獨聲明成一個變量來使用盅藻。
typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
- 如果分行顯示的話糜颠,block的右括號應該和調用block那行代碼的第一個非空字符對齊汹族。
- block內的代碼注意縮進對齊。
- ^ 和左括號 ( 或者 { 之間沒有空格其兴,參數(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ù)注釋時仿便,將光標移到函數(shù)行体啰,使用option+command+/快捷鍵來生成注釋。
- 對delegate和dataSource實現(xiàn)時嗽仪,在第一個函數(shù)前面#pragma mark - xxx來進行標注荒勇。
警告??
盡量減少??的產生,能修改的要及時修改闻坚。