代碼規(guī)范

第二版 2017.1.6

第三版 2018.8.29

以下規(guī)范基于 Coding Guidelines for Cocoa - Apple & 唐巧的博客


留白

  • 使用tab而不是空格
  • 使用留白劃分程序邏輯塊
  • 方法名過(guò)長(zhǎng)時(shí)注意換行:盡量讓代碼保持在120列之內(nèi); 通過(guò)設(shè)置 Xcode > Preferences > Text Editing > Show page guide,來(lái)使越界更容易被發(fā)現(xiàn)
    應(yīng)該
// blocks are easily readable
[UIView animateWithDuration:1.0 animations:^{
  // something
} completion:^(BOOL finished) {
  // something
}];

不應(yīng)該

// colon-aligning makes the block indentation hard to read
[UIView animateWithDuration:1.0
                 animations:^{
                     // something
                 }
                 completion:^(BOOL finished) {
                     // something
                 }];

不應(yīng)該

 if([MePagePushManager shareInstance].isPushRegiste
       &&[MePagePushManager shareInstance].isPushAvailable){
        [[MePagePushManager shareInstance] updatePushToken];
    }

命名

目的:簡(jiǎn)潔易懂

  • 使用駝峰格式命名,請(qǐng)不要使用駝峰和XXX_XXX混用,統(tǒng)一命名格式;
  • 文件命名前綴:
    • 當(dāng)與系統(tǒng)和第三方命名沖突時(shí)添加前綴以示區(qū)分;如:WBImageView
    • 當(dāng)被提供為SDK時(shí),使用前綴,以示歸屬;如:SiaoFloatView;在項(xiàng)目中可用Bridge或者子類方式轉(zhuǎn)換文件名,如:上述的SiaoFloatView,可用Bridge.h宏文件替換命名,或者 子類化出FloatView;
  • 文件、類、變量命名應(yīng)使用英文名稱
    • 不使用拼音;
    • 不使用毫無(wú)意義的簡(jiǎn)短的英文字母,名稱應(yīng)盡量描述出含義;
    • 請(qǐng)勿使用個(gè)人名字相關(guān)的命名;第三方框架除外.
    • 命名單詞盡量寫全;如:button,view.
    • 類名首字母大寫,方法首字母小寫,方法中的參數(shù)首字母小寫,同時(shí)盡量讓方法的命名讀起來(lái)像一句話,能夠傳達(dá)出方法的意思;
  • 以上命名,做到顧名思義,這樣的方法名和變量名無(wú)需添加注釋。
  • 方法命名應(yīng)該和apple官方命名一致
    應(yīng)該
- (UIView *)viewWithModel:(Model *)model other:(id)other {
  NSInteger i = height + 5 * 2;//應(yīng)該用空格隔開
}

不應(yīng)該

-(UIView*)viewWithModel:(Model *)model other:(id)other {
     NSInteger i = height+5*2;
}

應(yīng)該

UIButton *settingsButton;
CGFloat view_height;//VIEW_HEIGHT;

不應(yīng)該

UIButton *setBut;

不應(yīng)該

CGFloat View_Height;

  • 點(diǎn)擊事件命名didClickSendButton; didTapBoxView; 等
  • 定義網(wǎng)絡(luò)請(qǐng)求,requestXXX,解析網(wǎng)絡(luò)請(qǐng)求dealWithXXXX;
- (void)requestHotlistData:(BOOL)loadMore completion:(void(^)(BOOL success))completion;
- (void)dealWithHotListResponseWithData:(NSArray *)data;

文檔和代碼組織

  • 數(shù)字注釋出含義
  • 參數(shù)不允許為nil時(shí),加注釋
  • 使用Use #pragma mark對(duì)功能實(shí)現(xiàn)和協(xié)議實(shí)現(xiàn)分組,如下示例
  • 清除警告,個(gè)人的提醒用//@todo yourname or //@waring yourname代替,這樣只需要在項(xiàng)目里搜索 @todo yourname就可以找到,團(tuán)隊(duì)協(xié)作 在不影響他人的情況下協(xié)同開發(fā);需要提醒大家的才用#warning ,保持項(xiàng)目的整潔,及時(shí)清除警告。
  • 文件自上到下從優(yōu)先級(jí)以及包含與被包含的關(guān)系排列,禁止無(wú)須排列;

應(yīng)該:


image.png

不應(yīng)該


image.png
if (model.more_info.text.length > 0) {
        height += comments.count > 0 ? 6.0 : 0.0;//有回復(fù)且有moreInfo 有一個(gè)上邊距 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

聲明

  • 如果屬性的可修改性是一個(gè)實(shí)現(xiàn)細(xì)節(jié),聲明不可修改屬性。這是一個(gè)合理的顯式的聲明實(shí)例變量的原因
  • 如果一個(gè)屬性只在init內(nèi)被賦值了一次,那么就聲明為readonly
  • 如果返回可修改對(duì)象,并且實(shí)現(xiàn)中不修改該對(duì)象,則屬性聲明為copy, strong應(yīng)該僅用于暴露一個(gè)可修改對(duì)象
  • 使用[setupProperty]給需要初始化的變量初始化;
  • _property&self.property
  • 懶加載的使用, 需要使用懶加載才使用,不應(yīng)該為了代碼簡(jiǎn)潔而使用.

大家知道,self.property 其實(shí)是調(diào)用了類的 [self property] 方法,所以這其實(shí)是有一層方法調(diào)用的隱藏,很多時(shí)候,我們需要延遲初使化一個(gè)類成員的時(shí)候,就會(huì)把這個(gè)成員的初使化方法寫在這個(gè) [self property] 方法的實(shí)現(xiàn)中。
那么問(wèn)題來(lái)了,當(dāng)你在閱讀別人代碼時(shí),看到 self.property 的時(shí)候,你會(huì)想:這里會(huì)不會(huì)有一些隱藏的函數(shù)實(shí)現(xiàn)?于是你需要跳轉(zhuǎn)到其方法實(shí)現(xiàn)中去查找。但是在實(shí)際開發(fā)中,大部分的 property 其實(shí)是使用編譯器自動(dòng)生成的 Getter 和 Setter 方法,于是你會(huì)找不到實(shí)現(xiàn),這個(gè)時(shí)候,你才知道:“哦,原來(lái)這段代碼并沒有做自定義的成員初使化工作”。
這種默認(rèn)的隱藏在代碼中多了,會(huì)影響代碼的閱讀和維護(hù)。其實(shí)大部分的類成員變量都需要在類初使化方法中賦值,大部分的 UIViewController 的成員變量,都需要在 viewDidLoad 方法中賦值。那既然這樣,不如直接在相應(yīng)的方法中用一個(gè)名為 setupProperty 方法直接進(jìn)行初使化。這樣的好處是,代碼的可讀性更好了,self.property 只有需要延遲初使化的情況下才被使用。

@property (attributes) id<Protocol> object;
@property (nonatomic, strong) NSObject<Protocol> *object;
@implementation WKHotSearchViewController{
    NSObject *_object;
}
  • Constructors 應(yīng)該返回instancetype而不是id

不應(yīng)該

- (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;
}

常量

  • 常量是容易重復(fù)被使用和無(wú)需通過(guò)查找和代替就能快速修改值。
  • 常量應(yīng)該使用static來(lái)聲明而不是使用#define,除非顯式地使用宏。
static NSString * const IDENTIFY = @"weibo.com";

static CGFloat const CELL_HEIGHT = 50.0;

枚舉

  • 按照系統(tǒng)的命名方式

應(yīng)該:

typedef NS_ENUM(NSInteger, PushType) {
    PushTypeUnknown,
    PushTypeArticleRemotePush, // 遠(yuǎn)程Push打開正文
    PushTypeArticleLocalPush, // 本地Push打開正文
};

注釋

  • 應(yīng)做到盡量代碼“自解釋”,而不需要再編寫注釋。
  • 當(dāng)需要注釋時(shí),注釋應(yīng)該用來(lái)解釋這段特殊代碼為什么要這樣做。
  • 不注釋代碼塊,無(wú)用的代碼直接刪除
  • 不要一行一個(gè)注釋,單行注釋,可加在代碼末尾;
  • 注釋不是分割行的標(biāo)記!
    應(yīng)該
@property (nonatomic,strong) UILabel *nickNameLab; // 昵稱 + 贊了你的評(píng)論

不應(yīng)該

    /* headerTop */
    WBHeadlineHeaderView *articleHeaderView;
    
    /* headerMiddle */
    UIView *headerMiddleView;
    WBArticleMedileHeaderView *continuseView;
  • 不清楚MiddleView是什么作用,加了無(wú)意義,等于沒加;

控制結(jié)構(gòu)

  • 除if (xxx) return; 的用法,if必須加括號(hào)
  • 所有左括號(hào)應(yīng)該和關(guān)聯(lián)的表達(dá)式同一行,結(jié)尾換行
  • 關(guān)鍵詞和括號(hào)間加空格
  • 括號(hào)和它包括的內(nèi)容間不加空格
if (somethingIsBad) return;

if (something == nil) {
    // do stuff
} else {
    // do other stuff
}
  • 黃金路徑,早返回
    應(yīng)該
- (void)someMethod {
  if (![someOther boolValue]) {
    return;
  }

  //Do something important
}

不應(yīng)該

- (void)someMethod {
  if ([someOther boolValue]) {
    //Do something important
  }
}

異常和錯(cuò)誤處理

  • 不用使用異常做控制流
  • 表示錯(cuò)誤,使用NSError **參數(shù),或者給ReactiveCocoa signal發(fā)一個(gè)錯(cuò)誤
  • 方法參數(shù)不匹配時(shí),使用NSAssert
  • 循環(huán)引用

對(duì)象語(yǔ)法

  • 數(shù)組和字典對(duì)象文法內(nèi)容兩邊使用一個(gè)空格
  • 字典文法中,鍵值和冒號(hào)之間不留空格,值和冒號(hào)之間使用一個(gè)空格
  • 數(shù)組和字典setObject時(shí)候需要保證object非nil
NSArray *theStuff = @[@1, @2, @3];

NSDictionary *keyedStuff = @{GHDidCreateStyleGuide: @YES};
  • 更長(zhǎng)或者更復(fù)雜的文法應(yīng)該分成多行(可選以逗號(hào)結(jié)尾)
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",
};

類的結(jié)構(gòu)

graph TD
A[LifeCycle] -->B(Request) 
B -->C(UITableViewDelegate&DataSource)
C -->D(...)
D -->E(Setter&Getter)

  • 注意Lazy init的用法
  • 精簡(jiǎn)VC

第三方庫(kù)引入

- 引入第三方庫(kù)前,需要充分調(diào)研該庫(kù)的質(zhì)量,引入github的庫(kù),原則上應(yīng)該star在500+以上才考慮
- 引入的庫(kù)若支持Pods管理,以Pods來(lái)組織代碼
- 引入的庫(kù)應(yīng)該保持代碼不變,在庫(kù)的上層進(jìn)行自定義,而不應(yīng)該修改庫(kù)本身

引用文件

  • 在.h中盡量使用@class(如果不需要知道引用文件的具體屬性),在.m文件中使用#import

擴(kuò)展

  • 擴(kuò)展應(yīng)該按照所提供的功能命名,不要?jiǎng)?chuàng)建保護(hù)傘拓展
  • 擴(kuò)展方法一定要加前綴
  • 如果你想給子類或者單元測(cè)試暴露私有方法,使用 Class+Private命名創(chuàng)建一個(gè)分類
- (void)pf_viewDidLoad
{
    [self pf_viewDidLoad];
}

兼容64位

  • 整型的聲明使用NSInteger
  • 浮點(diǎn)使用CGFloat(UI相關(guān))和double
  • 字符串占位符不再使用%d, %ld, 將對(duì)應(yīng)的整型使用對(duì)象文法包裝,并使用%@的打印 [NSString stringWithFormat:@"%@", @(intVar)]
  • 枚舉定義采用新風(fēng)格(NS_ENUM),并指定類型為NSInteger
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容