代碼規(guī)范

第二版 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)先級以及包含與被包含的關系排列,禁止無須排列;

應該:


image.png

不應該


image.png
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
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容

  • iOS編程規(guī)范0規(guī)范 0.1前言 為??高產(chǎn)品代碼質量,指導廣大軟件開發(fā)人員編寫出簡潔、可維護、可靠、可 測試、高效...
    iOS行者閱讀 4,476評論 21 35
  • 推薦文章:禪與 Objective-C 編程藝 前言 為??高產(chǎn)品代碼質量,指導廣大軟件開發(fā)人員編寫出簡潔、可維護、...
    WolfTin閱讀 2,796評論 0 1
  • 代碼格式 使用空格而不是制表符 Tab 不要在工程里使用 Tab 鍵,使用空格來進行縮進。在 Xcode > Pr...
    small_Sun閱讀 1,377評論 1 3
  • 示例 下面是一個示例頭文件,演示了@interface聲明的正確注釋和間隔 一個示例源文件,演示了一個接口的@ i...
    我是Damo閱讀 2,035評論 2 5
  • 要想給生命當家做主,平時就要惜福,把能量留下來,讓它變成“善終”“長壽”。 終是個什么狀態(tài)呢?無疾而終,壽終正寢。...
    蘭州理工大學管理員閱讀 291評論 0 0