[iOS-Objective-C] 編碼規范

參考

The official raywenderlich.com Objective-C style guide.
Objective-C編碼規范:26個方面解決iOS開發問題
自動格式化工具:XcodeClangFormat
Coding Guidelines for Cocoa

規范

  1. 統一使用US英語。

    符合規則的:

    UIColor *myColor = [UIColor whiteColor];
    

    不符合規則的:

    UIColor *myColour = [UIColor whiteColor];  
    UIColor *yanse = [UIColor whiteColor];
    
  2. #import "xxx.h"的排序:以對應的頭文件開始,之后是項目內創建的其他文件,下一部分為所有的 Category 文件,最后是第三方庫文件。本項目所創建文件部分的排序為:Controller 層文件,View 層文件,Model 層文件,數據層文件,工具類文件。Category 文件部分的排序為:項目內文件的 Category,Foundation 類的 Category,UIKit 類的 Category,第三方庫類的 Category。

  3. 使用#pragma mark -對方法進行分類。

    符合規則的:

    #pragma mark - Override //重寫方法
    
    - (instancetype)init {}  
    
    - (void)dealloc {}  
    
    - (void)viewDidLoad {}
    
    - (void)viewWillAppear:(BOOL)animated {}  
    
    - (void)didReceiveMemoryWarning {} 
    
    #pragma mark - Public //公有方法 
    
    - (void)publicMethod {} 
    
    #pragma mark - Responder //響應事件的方法,包括處理通知的方法
    
    - (IBAction)submitData:(id)sender {}  
    
    - (void)handleNotification:(NSNotification *)notification {}
    
    #pragma mark - Delegate //代理實現方法(以相應協議名命名)
    
    #pragma mark - Private //私有方法
    
    - (void)privateMethod {}  
    
    #pragma mark - Setter //Setter方法
    
    - (void)setCustomProperty:(id)value {}  
    
    #pragma mark - Getter //Getter方法,通常實現懶加載  
    
    - (id)customProperty {}
    
  4. 在.h文件中方法都為 Public,若較多則以功能劃分,與#pragma mark -間不空行,@property間不空行,但兩部分之間空一行。

    符合規則的:

    @property NSString (nonatomic) *name;
    @property NSInteger length;
    
    #pragma mark - Category
    - (instancetype)init {}  
    - (void)dealloc {}  
    - (void)viewDidLoad {}
    - (void)viewWillAppear:(BOOL)animated {}  
    - (void)didReceiveMemoryWarning {}   
    

    不符合規則的:

    @property NSString (nonatomic) *name;
    
    @property NSInteger length;
    
    #pragma mark - Category
    
    - (instancetype)init {}
    
    - (void)dealloc {}  
    
    - (void)viewDidLoad {}
    
    - (void)viewWillAppear:(BOOL)animated {}
      
    - (void)didReceiveMemoryWarning {} 
    
  5. 在.m文件中方法以及#pragma mark -間空一行。

    符合規則的:

    #pragma mark - Override
    
    - (instancetype)init {}  
    
    - (void)dealloc {}  
    
    - (void)viewDidLoad {}
    
    - (void)viewWillAppear:(BOOL)animated {}  
    
    - (void)didReceiveMemoryWarning {}   
    

    不符合規則的:

    #pragma mark - Override
    - (instancetype)init {}  
    - (void)dealloc {}  
    - (void)viewDidLoad {}
    - (void)viewWillAppear:(BOOL)animated {}  
    - (void)didReceiveMemoryWarning {}
    
  6. @property的默認屬性值不寫,只注明非默認值。

    符合規則的:

    @property (weak, nonatomic) NSString *property1;
    @property (nonatomic) NSString *property2;
    @property NSString *property3;
    

    不符合規則的:

    @property (strong, atomic) NSString *property1;
    
  7. 選擇,循環結構語句塊與上一條語句之間空一行,若在方法的第一行則不需要空行。

    符合規則的:

    NSInteger a;
    NSInteger b;
    
    if (a > b) {
        NSLog(@"a > b");
    }
    

    不符合規則的:

    NSInteger a;
    NSInteger b;
    if (a > b) {
        NSLog(@"a > b");
    }
    
  8. block 代碼塊與上一條語句之間空一行,若在方法的第一行則不需要空行。

    符合規則的:

    NSInteger a;
    NSInteger b;
    
    [UIView animateWithDuration:1.0 animations:^{  
        // something  
    }];
    

    不符合規則的:

    NSInteger a;
    NSInteger b;
    [UIView animateWithDuration:1.0 animations:^{  
        // something  
    }];
    
  9. 縮進使用4個空格,可在 Xcode 中的Preferences->Text Editing->Indentation中設置。

  10. 空行中不要留有空字符,可在 Xcode 中的Preferences->Text Editing->Editing中設置。

  11. 方法及其他語句塊的大括號總是在同一行語句打開但在新行中關閉。

    符合規則的:

    if (success) {  
        //Do something  
    } else {  
        //Do something else  
    }
    

    不符合規則的:

    if (success)
    {  
        //Do something  
    } else 
    {  
        //Do something else  
    }
    
  12. 選擇,循環結構語句塊中關鍵字,條件,大括號之間都有一個空格。

    符合規則的:

    if (success) {  
        //Do something  
    } else {  
        //Do something else  
    }
    

    不符合規則的:

    if(success){  
        //Do something  
    }else{  
        //Do something else  
    }
    
  13. return語句前空一行。

    符合規則的:

    - (NSString *)method {
        NSString *string = @"";
    
        return string;
    }
    

    不符合規則的:

    - (NSString *)method {
        NSString *string = @"";
        return string;
    }
    
  14. 避免以冒號對齊的方式來聲明,定義和調用方法。

    符合規則的:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    }
    
    // blocks are easily readable  
    [UIView animateWithDuration:1.0 animations:^{  
    // something  
    } completion:^(BOOL finished) {  
    // something  
    }];
    

    不符合規則的:

    - (UITableViewCell *)tableView:(UITableView *)tableView
             cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    }
    
    // colon-aligning makes the block indentation hard to read  
    [UIView animateWithDuration:1.0  
                     animations:^{  
                         // something  
                     }  
                     completion:^(BOOL finished) {  
                         // something  
                     }]; 
    
  15. 方法定義時,修飾符與返回類型之間有一個空格,方法名與其后的開始大括號之間有一個空格。在方法各個段之間應該也有一個空格,在參數之前應該包含一個具有描述性的關鍵字來描述參數。不要使用and作為多個參數的說明。各參數段的說明,首字母也要小寫。

    符合規則的:

    - (void)method {
    }
    - (void)setExampleText:(NSString *)text image:(UIImage *)image;
    - (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;
    - (id)viewWithTag:(NSInteger)tag;
    - (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
    

    不符合規則的:

    -(void)method{
    }
    -(void)setT:(NSString *)text i:(UIImage *)image;
    - (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
    - (id)taggedView:(NSInteger)tag;
    - (instancetype)initWithWidth:(CGFloat)width AndHeight:(CGFloat)height;
    - (instancetype)initWith:(int)width And:(int)height;  // Never do this.
    
  16. 統一使用語法糖。特別注意 nil 值不能傳入 NSArray 和
    NSDictionary 字面值,因為這樣會導致 crash。

    符合規則的:

    @property (nonatomic) NSString *string;
    
    - (void)text {
        NSString *localString = self.string;
        self.string = @"";
        NSNumber *number = @(1);
        NSDictionary *dictionary = @{@"value1":@"key1"};
        NSString *value1 = dictionary[@"key1"];
        NSArray *array = @[@"value"];
        NSString *value = array[1];
    }
    

    不符合規則的:

    @property (nonatomic) NSString *string;
    
    - (void)text {
        NSString *localString = [self string];
        [self setString:@""];
        NSNumber *number = [NSNumber numberWithInt:1];
        NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"value1",@"key1", nil];
        NSString *value1 = [dictionary objectForKey:@"key1"];
        NSArray *array = [NSArray arrayWithObjects:@"value", nil];
        NSArray *array = @[@"value", nil];
        NSString *value = [array objectAtIndex:1];
    }
    
  17. 注釋應該用來解釋這段特殊代碼為什么要這樣做,而不是翻譯代碼做了什么。任何被使用的注釋都必須保持最新或被刪除。

  18. 由于Objective-C中沒有命名空間的概念,所以一般會在所有類前加一個項目自定義的大寫縮寫前綴,一般為兩到三個字符。盡量使用描述完整的變量名(包括property)和方法名,因為有編輯器的自動提示功能,可以允許命名較長,使用駝峰式命名規則,但首字母要小寫,變量命名的一個原則是在變量名的最后指明變量的類型。

    符合規則的:

    UIButton *settingsButton;
    NSArray *viewArray = [[NSBundle mainBundle] loadNibNamed:@"" owner:nil options:nil];
    

    不符合規則的:

    UIButton *setBut;
    NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"" owner:nil options:nil];
    
  19. 常量應該使用駝峰式命名規則。全局常量以小寫的字母k加項目前綴開頭,一個類內部使用的靜態常量則不需要加項目前綴,之后所有的單詞首字母大寫。

    符合規則的:

    NSString const* kSRMConstString = @"";
    static NSString const* kSRMStaticConstString = @"";
    

    不符合規則的:

    static NSString const* constString = @"";
    
  20. 局部變量的命名不要以下劃線開始,以便和 property 默認生成的成員變量區別。除了 property 的 setter 和 getter 方法外,如果沒有特殊情況,不要使用默認生成的變量,應直接操作屬性。

  21. 統一使用屬性,避免使用成員變量。屬性完全可以替代成員變量,當不對 setter 和 getter 方法進行自定義時,屬性與成員變量效果一致,使用屬性可以靈活的隨時加以額外的處理。

    符合規則的:

    @interface SRClass: NSObject  
    @property (nonatomic) NSString *variable;  
    @end
    

    不符合規則的:

    @interface SRClass: NSObject {  
        NSString *variable;  
    }
    
  22. 星號表示聲明的變量是指針類型

    符合規則的:

    NSString *string = @"";
    

    不符合規則的:

    NSString * string = @"";
    NSString* string = @"";
    

    特殊情況:

    NSString *const string= @"";
    
  23. NSString、NSDictionary、NSArray 應該使用 copy 屬性特性。即使你聲明的是以上類型的屬性,有人可能傳入一個對應的可變版本的實例,然后在你沒有注意的情況下修改它

    符合規則的:

    @property (copy, nonatomic) NSString *variable;
    

    不符合規則的:

    @property (nonatomic) NSString *variable;
    
  24. 關于代碼段中其他情況的空行,super 的方法可以在方法中的任意位置調用,所以 super 方法調用的代碼前后不需要空行,原則上除相應語法代碼段的空行外在方法中不出現其他空行,如果兩個代碼段之間需要空行區分,考慮是否應分成兩個新方法。如果真的有需要空行區分,可以加一行簡單注釋分隔,不空行。

  25. 不使用宏來定義常量,常量是容易重復被使用且無需通過查找和代替就能快速修改值。常量應該使用 const 來聲明而不是使用#define。

    符合規則的:

    NSString *const kSRString = @"string";
    static CGFloat const kStaticFloat = 50.0;
    

    不符合規則的:

    #define kSRString @"string"  
    #define kSRStaticFloat 50.0
    
  26. 文件內部使用的字符串常量

    static NSString *const kFoo = @"Foo";
    

    供多個模塊使用的公共字符串常量,名稱要加項目縮寫前綴

    // .m 文件中
    NSString *const Foo = @"Foo";
    // .h 文件中
    extern NSString *const Foo;
    

    常量名以小寫字母 k 開頭是參照匈牙利命名法(Hungarian Notation),表示常量 constant 的意思。內部常量使用這一規則,以便和變量名進行區分。UIKit 不使用這一規范,直接以縮寫前綴開始。所以公共常量直接以縮寫前綴開始。

  27. 當定義枚舉類型時,使用新的固定基本類型規格,因為它有更強的類型檢查和代碼補全。現在SDK有一個宏 NS_ENUM() 來幫助和鼓勵你使用固定的基本類型。

    符合規則的:

    typedef NS_ENUM(NSInteger, SREnumType) {  
        SREnumTypeA,  
        SREnumTypeB,  
        SREnumTypeC  
    }; 
    

    不符合規則的:

    enum SREnumType {  
        SREnumTypeA,  
        SREnumTypeB,  
        SREnumTypeC  
    };
    
  28. 當在 case 語句塊中聲明變量,則該 case 語句塊必須被大括號包圍,若一個
    case 語句塊中沒有聲明變量,則不加大括號。當switch枚舉所有類型時,'default'是不需要的

    符合規則的:

    switch(SREnumType) {
        case SREnumTypeA:
        case SREnumTypeB: {
              NSString *emptyString = @"";
              // code
        }
              break;
        case SREnumTypeC:
              // code
              break;
    }
    
  29. 私有屬性應該在類的實現文件中的類擴展(匿名分類)中聲明。

    符合規則的:

    @interface SRViewController ()  
    
    @property (nonatomic) GADBannerView *googleAdView; 
    @property (nonatomic) ADBannerView *iAdView;  
    @property (nonatomic) UIWebView *adXWebView;
    
    @end
    
  30. Objective-C 使用 YES 和 NO。因為 true 和 false 應該只在
    CoreFoundation,C 或 C++ 代碼使用。既然 nil 解析成 NO,所以沒有必要在條件語句比較。不要拿某樣東西直接與 YES 比較,因為YES被定義為1而一個 BOOL
    能被設置為8位。

    符合規則的:

    if (someObject) {
    }  
    
    if (![anotherObject boolValue]) {
    } 
    

    不符合規則的:

    if (someObject == nil) {}  
    if ([anotherObject boolValue] == NO) {}  
    if (isAwesome == YES) {} // Never do this.  
    if (isAwesome == true) {} // Never do this.
    
  31. 條件語句主體必須使用大括號包圍,即使只有一行代碼

    符合規則的:

    if (!error) {  
        return success;  
    } 
    

    不符合規則的:

    if (!error)  
        return success; 
    //or
    if (!error) return success;
    
  32. 當需要提高代碼的清晰性和簡潔性時,三元操作符?:才會使用。單個條件求值常常需要它。多個條件求值時,如果使用if語句或重構成實例變量時,代碼會更加易讀。一般來說,最好使用三元操作符是在根據條件來賦值的情況下。Non-boolean的變量與某東西比較,加上括號()會提高可讀性。如果被比較的變量是boolean類型,那么就不需要括號。

    符合規則的:

    NSInteger value = 5;  
    result = (value != 0) ? x : y;  
    BOOL isHorizontal = YES;  
    result = isHorizontal ? x : y;
    

    不符合規則的:

    result = a > b ? x = c > d ? c : d : y;
    
  33. Init 方法應該遵循 Apple 生成代碼模板的命名規則,返回類型應該使用 instancetype 而不是 id。

    符合規則的:

    - (instancetype)init {  
        self = [super init];  
    
        if (self) {  
            // ...  
        }  
    
        return self;  
    }
    
  34. 當類構造方法被使用時,它應該返回類型是 instancetype 而不是
    id。這樣確保編譯器正確地推斷結果類型。

    符合規則的:

    @interface Airplane  
    + (instancetype)airplaneWithType:(RWTAirplaneType)type;  
    @end
    
  35. 當訪問 CGRect 里的 x、y、width 或 height 時,應該使用CGGeometry 函數而不是直接通過結構體來訪問。引用Apple的CGGeometry:

    在這個參考文檔中所有的函數,接受CGRect結構體作為輸入,在計算它們結果時隱式地標準化這些rectangles。因此,你的應用程序應該避免直接訪問和修改保存在CGRect數據結構中的數據。相反,使用這些函數來操縱rectangles和獲取它們的特性。

    符合規則的:

    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);
    

    不符合規則的:

    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 };
    
  36. 當使用條件語句編碼時,左手邊的代碼應該是"golden" 或 "happy"路徑。也就是不要嵌套if語句,多個返回語句也是OK。

    符合規則的:

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

    不符合規則的:

    - (void)someMethod {  
        if ([someOther boolValue]) {  
            //Do something important  
        }  
    }
    
  37. 當方法通過引用來返回一個錯誤參數,判斷返回值而不是錯誤變量。在成功的情況下,有些Apple的APIs記錄垃圾值(garbage values)到錯誤參數(如果non-NULL),那么判斷錯誤值會導致false負值和crash。

    符合規則的:

    NSError *error;  
    
    if (![self trySomethingWithError:&error]) {  
        // Handle Error  
    } 
    

    不符合規則的:

    NSError *error;  
    [self trySomethingWithError:&error]; 
    
    if (error) {  
        // Handle Error  
    } 
    
  38. 單例對象應該使用線程安全模式來創建共享實例。

    符合規則的:

    + (instancetype)sharedInstance {  
        static id sharedInstance = nil;  
        static dispatch_once_t onceToken;  
        dispatch_once(&onceToken, ^{  
            sharedInstance = [[self alloc] init];  
        });  
    
        return sharedInstance;  
    }
    

    不符合規則的:

    + (instancetype)sharedInstance {
         static MyClass *shared = nil;
    
         if(shared == nil) {
            shared = [[MyClass alloc] init];
         }
    
         return shared;
    }
    
  39. 物理文件目錄應該與 Xcode 工程文件目錄保持同步來避免文件擴張。任何Xcode分組的創建應該在文件系統的文件體現。代碼不僅是根據類型來分組,而且還可以根據功能來分組,這樣代碼更加清晰。

  40. 除了使用帶參數的init方法初始化實例時與alloc方法鏈式調用,其他情況一般不鏈式調用。

    符合規則的:

    MyClass *myClass = [[MyClass alloc] initWithName:@""];
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter addObserver:self selector:@selector(disposeNotification:) name:SRNotification object:nil];
    

    不符合規則的:

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disposeNotification:) name:SRNotification object:nil];
    
  41. 當變量不使用默認的 strong 進行修飾時,需明確寫出指定的修飾符

    符合規則的:

    MyClass * __weak myWeakReference;
    MyClass * __unsafe_unretained myUnsafeReference;
    

    不符合規則的:

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

推薦閱讀更多精彩內容