iOS編碼規(guī)范

總體命名規(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>,除了一些特殊情況下常量。

  1. 類成員變量

    類中所有成員變量以屬性的方式提供,不要使用其他類型的變量聲明。

    通過使用'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;
        }
    
  2. 私有屬性應(yīng)該聲明在類的.m中,只有需要外部使用的變量才聲明在.h中。

  3. 所有屬性特性應(yīng)該顯式地列出來,有助于新手閱讀代碼。屬性特性的順序應(yīng)該是atomicity、storage。

    應(yīng)該:

    @property (nonatomic, strong) NSString *name;
    

    不應(yīng)該:

    @property (nonatomic) NSString *testName;
    
  4. 屬性是指針類型的集合時,格式如下:
    @property (nonatomic, strong) NSArray <Item *>*array;

  5. 屬性是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];

操作符

一元操作符不帶空格,多元運算符要帶空格隔開。

  1. 逗號后面都要跟隨一個空格。

    NSArray *array = @[1, 2, 3, 4];

  2. 二元操作符,如+, -, *, /,>, <, =, ==, ->, <<, >>等。

    a + b = c;
    a > b;
    a == b;
    a << 2;
    Object -> c;
    
  3. 三元操作符 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)生,能修改的要及時修改。

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

推薦閱讀更多精彩內(nèi)容

  • 摘要 為了規(guī)范看準(zhǔn)iOS編碼而作。主要包含編碼格式和命名規(guī)范兩大章節(jié)。 在寫之前對下面所用的有些詞匯進行一些約定:...
    叫我公爵大人閱讀 290評論 0 1
  • Object-C 開發(fā)代碼規(guī)范概要Object-C是一門面向?qū)ο蟮膭討B(tài)編程語言,主要用于編寫IOS和MAC應(yīng)用程序...
    克魯?shù)吕?/span>閱讀 546評論 0 1
  • 在開發(fā)過程中,我們不僅要去看別人的代碼,也要讓別人看我們的代碼。每個人的Objective-C編碼風(fēng)格都不一樣,這...
    叫我GuanRen閱讀 191評論 0 1
  • 面試被問到公司編碼規(guī)范問題,感覺有很多東西,但是不知道該怎么說出來,今天突然找到 李明杰 老師的一份編碼規(guī)范。重新...
    Dombo_Y閱讀 984評論 1 2
  • ——書法班老師布置的作業(yè)(臨褚遂良) ——某同學(xué)的作業(yè)(是不是形神兼?zhèn)洌浚?我在味古方室書法培訓(xùn)機構(gòu)里已經(jīng)進過四次...
    金垛愚叟閱讀 357評論 0 0