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,所以沒有必要在條件語句比較。不要拿某樣東西直接與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)一風格。修改者要遵循創(chuà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方法進行標注。
  • 相同delegate和datasource的函數(shù)放在一起,并用pragma mark - xxx標注。

init方法

Init方法應(yīng)該遵循Apple生成代碼模板的命名規(guī)則。返回類型應(yīng)該使用instancetype而不是id。

- (instancetype)init {
  self = [super init];
  if (self) {
    // ...
  }
  return self;
}

類構(gòu)造方法

當類構(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ù)

當訪問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ù)注釋時,將光標移到函數(shù)行,使用option+command+/快捷鍵來生成注釋。
  • 對delegate和dataSource實現(xiàn)時,在第一個函數(shù)前面#pragma mark - xxx來進行標注。

警告??

盡量減少??的產(chǎn)生,能修改的要及時修改。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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

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