第二版 2017.1.6
第三版 2018.8.29
以下規(guī)范基于 Coding Guidelines for Cocoa - Apple & 唐巧的博客
留白
- 使用tab而不是空格
- 使用留白劃分程序邏輯塊
- 方法名過長時注意換行:盡量讓代碼保持在120列之內; 通過設置 Xcode > Preferences > Text Editing > Show page guide,來使越界更容易被發(fā)現(xiàn)
應該
// blocks are easily readable
[UIView animateWithDuration:1.0 animations:^{
// something
} completion:^(BOOL finished) {
// something
}];
不應該
// colon-aligning makes the block indentation hard to read
[UIView animateWithDuration:1.0
animations:^{
// something
}
completion:^(BOOL finished) {
// something
}];
不應該
if([MePagePushManager shareInstance].isPushRegiste
&&[MePagePushManager shareInstance].isPushAvailable){
[[MePagePushManager shareInstance] updatePushToken];
}
命名
目的:簡潔易懂
- 使用駝峰格式命名,請不要使用駝峰和XXX_XXX混用,統(tǒng)一命名格式;
- 文件命名前綴:
- 當與系統(tǒng)和第三方命名沖突時添加前綴以示區(qū)分;如:WBImageView
- 當被提供為SDK時,使用前綴,以示歸屬;如:SiaoFloatView;在項目中可用Bridge或者子類方式轉換文件名,如:上述的SiaoFloatView,可用Bridge.h宏文件替換命名,或者 子類化出FloatView;
- 文件、類、變量命名應使用英文名稱
- 不使用拼音;
- 不使用毫無意義的簡短的英文字母,名稱應盡量描述出含義;
- 請勿使用個人名字相關的命名;第三方框架除外.
- 命名單詞盡量寫全;如:button,view.
- 類名首字母大寫,方法首字母小寫,方法中的參數(shù)首字母小寫,同時盡量讓方法的命名讀起來像一句話,能夠傳達出方法的意思;
- 以上命名,做到顧名思義,這樣的方法名和變量名無需添加注釋。
- 方法命名應該和apple官方命名一致
應該
- (UIView *)viewWithModel:(Model *)model other:(id)other {
NSInteger i = height + 5 * 2;//應該用空格隔開
}
不應該
-(UIView*)viewWithModel:(Model *)model other:(id)other {
NSInteger i = height+5*2;
}
應該
UIButton *settingsButton;
CGFloat view_height;//VIEW_HEIGHT;
不應該
UIButton *setBut;
不應該
CGFloat View_Height;
- 點擊事件命名didClickSendButton; didTapBoxView; 等
- 定義網(wǎng)絡請求,requestXXX,解析網(wǎng)絡請求dealWithXXXX;
- (void)requestHotlistData:(BOOL)loadMore completion:(void(^)(BOOL success))completion;
- (void)dealWithHotListResponseWithData:(NSArray *)data;
文檔和代碼組織
- 數(shù)字注釋出含義
- 參數(shù)不允許為nil時,加注釋
- 使用Use #pragma mark對功能實現(xiàn)和協(xié)議實現(xiàn)分組,如下示例
- 清除警告,個人的提醒用//@todo yourname or //@waring yourname代替,這樣只需要在項目里搜索 @todo yourname就可以找到,團隊協(xié)作 在不影響他人的情況下協(xié)同開發(fā);需要提醒大家的才用#warning ,保持項目的整潔,及時清除警告。
- 文件自上到下從優(yōu)先級以及包含與被包含的關系排列,禁止無須排列;
應該:
不應該
if (model.more_info.text.length > 0) {
height += comments.count > 0 ? 6.0 : 0.0;//有回復且有moreInfo 有一個上邊距 6
height += [self moreInfoHeight];
} else {
height -= 1;//由于為了適配有表情的行高(+2) 這里減去2
}
#pragma mark Properties
@dynamic someProperty;
- (void)setCustomProperty:(id)value {}
#pragma mark Lifecycle
+ (id)objectWithThing:(id)thing {}
- (instancetype)init {}
//@todo xiaodong
//@warning xiaodong
聲明
- 如果屬性的可修改性是一個實現(xiàn)細節(jié),聲明不可修改屬性。這是一個合理的顯式的聲明實例變量的原因
- 如果一個屬性只在init內被賦值了一次,那么就聲明為readonly
- 如果返回可修改對象,并且實現(xiàn)中不修改該對象,則屬性聲明為copy, strong應該僅用于暴露一個可修改對象
- 使用[setupProperty]給需要初始化的變量初始化;
- _property&self.property
- 懶加載的使用, 需要使用懶加載才使用,不應該為了代碼簡潔而使用.
大家知道,self.property 其實是調用了類的 [self property] 方法,所以這其實是有一層方法調用的隱藏,很多時候,我們需要延遲初使化一個類成員的時候,就會把這個成員的初使化方法寫在這個 [self property] 方法的實現(xiàn)中。
那么問題來了,當你在閱讀別人代碼時,看到 self.property 的時候,你會想:這里會不會有一些隱藏的函數(shù)實現(xiàn)?于是你需要跳轉到其方法實現(xiàn)中去查找。但是在實際開發(fā)中,大部分的 property 其實是使用編譯器自動生成的 Getter 和 Setter 方法,于是你會找不到實現(xiàn),這個時候,你才知道:“哦,原來這段代碼并沒有做自定義的成員初使化工作”。
這種默認的隱藏在代碼中多了,會影響代碼的閱讀和維護。其實大部分的類成員變量都需要在類初使化方法中賦值,大部分的 UIViewController 的成員變量,都需要在 viewDidLoad 方法中賦值。那既然這樣,不如直接在相應的方法中用一個名為 setupProperty 方法直接進行初使化。這樣的好處是,代碼的可讀性更好了,self.property 只有需要延遲初使化的情況下才被使用。
@property (attributes) id<Protocol> object;
@property (nonatomic, strong) NSObject<Protocol> *object;
@implementation WKHotSearchViewController{
NSObject *_object;
}
- Constructors 應該返回instancetype而不是id
不應該
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self.container addSubview:self.userIconImg];
[self.container addSubview:self.nickNameLab];
[self.container addSubview:self.timeLab];
[self.container addSubview:self.contentImg];
[self.container addSubview:self.contentLab];
[self.container addSubview:self.bottomLine];
[self.contentView addSubview:self.container];
[self addMasonry];
}
return self;
}
常量
- 常量是容易重復被使用和無需通過查找和代替就能快速修改值。
- 常量應該使用static來聲明而不是使用#define,除非顯式地使用宏。
static NSString * const IDENTIFY = @"weibo.com";
static CGFloat const CELL_HEIGHT = 50.0;
枚舉
- 按照系統(tǒng)的命名方式
應該:
typedef NS_ENUM(NSInteger, PushType) {
PushTypeUnknown,
PushTypeArticleRemotePush, // 遠程Push打開正文
PushTypeArticleLocalPush, // 本地Push打開正文
};
注釋
- 應做到盡量代碼“自解釋”,而不需要再編寫注釋。
- 當需要注釋時,注釋應該用來解釋這段特殊代碼為什么要這樣做。
- 不注釋代碼塊,無用的代碼直接刪除
- 不要一行一個注釋,單行注釋,可加在代碼末尾;
- 注釋不是分割行的標記!
應該
@property (nonatomic,strong) UILabel *nickNameLab; // 昵稱 + 贊了你的評論
不應該
/* headerTop */
WBHeadlineHeaderView *articleHeaderView;
/* headerMiddle */
UIView *headerMiddleView;
WBArticleMedileHeaderView *continuseView;
- 不清楚MiddleView是什么作用,加了無意義,等于沒加;
控制結構
- 除if (xxx) return; 的用法,if必須加括號
- 所有左括號應該和關聯(lián)的表達式同一行,結尾換行
- 關鍵詞和括號間加空格
- 括號和它包括的內容間不加空格
if (somethingIsBad) return;
if (something == nil) {
// do stuff
} else {
// do other stuff
}
- 黃金路徑,早返回
應該
- (void)someMethod {
if (![someOther boolValue]) {
return;
}
//Do something important
}
不應該
- (void)someMethod {
if ([someOther boolValue]) {
//Do something important
}
}
異常和錯誤處理
- 不用使用異常做控制流
- 表示錯誤,使用NSError **參數(shù),或者給ReactiveCocoa signal發(fā)一個錯誤
- 方法參數(shù)不匹配時,使用NSAssert
- 循環(huán)引用
對象語法
- 數(shù)組和字典對象文法內容兩邊使用一個空格
- 字典文法中,鍵值和冒號之間不留空格,值和冒號之間使用一個空格
- 數(shù)組和字典setObject時候需要保證object非nil
NSArray *theStuff = @[@1, @2, @3];
NSDictionary *keyedStuff = @{GHDidCreateStyleGuide: @YES};
- 更長或者更復雜的文法應該分成多行(可選以逗號結尾)
NSArray *theStuff = @[
@"Got some long string objects in here.",
[AndSomeModelObjects too],
@"Moar strings."
];
NSDictionary *keyedStuff = @{
@"this.key": @"corresponds to this value",
@"otherKey": @"remoteData.payload",
@"some": @"more",
@"JSON": @"keys",
@"and": @"stuff",
};
類的結構
graph TD
A[LifeCycle] -->B(Request)
B -->C(UITableViewDelegate&DataSource)
C -->D(...)
D -->E(Setter&Getter)
- 注意Lazy init的用法
- 精簡VC
第三方庫引入
- 引入第三方庫前,需要充分調研該庫的質量,引入github的庫,原則上應該star在500+以上才考慮
- 引入的庫若支持Pods管理,以Pods來組織代碼
- 引入的庫應該保持代碼不變,在庫的上層進行自定義,而不應該修改庫本身
引用文件
- 在.h中盡量使用@class(如果不需要知道引用文件的具體屬性),在.m文件中使用#import
擴展
- 擴展應該按照所提供的功能命名,不要創(chuàng)建保護傘拓展
- 擴展方法一定要加前綴
- 如果你想給子類或者單元測試暴露私有方法,使用 Class+Private命名創(chuàng)建一個分類
- (void)pf_viewDidLoad
{
[self pf_viewDidLoad];
}
兼容64位
- 整型的聲明使用NSInteger
- 浮點使用CGFloat(UI相關)和double
- 字符串占位符不再使用%d, %ld, 將對應的整型使用對象文法包裝,并使用%@的打印 [NSString stringWithFormat:@"%@", @(intVar)]
- 枚舉定義采用新風格(NS_ENUM),并指定類型為NSInteger