Objective-C编码规范

前段时间接手了一个开发三年之久的老项目,三年期间经历了5-6个程序员的开发,整个项目架构比较混乱,代码风格差距很大,也有许多不规范代码,难以Code Review。对于承担这个项目的维护、部分代码重构以及后续产品开发的责任,我拟定了这个迟到了三年之久的项目代码规范,要求所有的iOS同事在之后的开发以及代码的重构过程中以此作为编码规范。此代码规范一直是我自身的代码规范,来源于几年前借鉴 raywenderlich的Objective-C style ,感兴趣的朋友可以去GitHub上自行搜索。

命名###

  • 变量的命名使用US英语,不可使用拼音代替;
  • 尽可能坚持Apple的命名规则,长的,描述性的方法和变量命名是最好的
    应该:
    UIButton *nextButton;
    UIlabel *nameLabel;
    或者可以使用简介的命名方式:
    UIButton *btn_next;
    UILabel *lb_name;
    切不可随意命名控件:
    UIButton *next;
    UILabel *name;
  • 变量的命名采用驼峰命名法则,并且单词的首字母需要小写
  • 星号表示变量是指针。例如, NSString *text 既不是 NSString* text 也不是 NSString * text,除了一些特殊情况下常量。

下划线###

  • 当使用属性时,实例变量应该使用self.来访问和改变。这就意味着所有属性将会视觉效果不同,因为它们前面都有self.当然,重写属性的set,get方法中等必须使用下划线的情况下使用下划线.

代码组织###

  • 使用#pragma mark -来分类方法,使得文件结构清晰,遵循以下一般结构:
    #pragma mark - Lifecycle

    - (instancetype)init {}
    - (void)dealloc {}
    - (void)viewDidLoad {}
    - (void)viewWillAppear:(BOOL)animated {}
    - (void)didReceiveMemoryWarning {}
    
    #pragma mark - Custom Accessors
    
    - (void)setCustomProperty:(id)value {}
    - (id)customProperty {}
    
    #pragma mark - IBActions
    
    - (IBAction)submitData:(id)sender {}
    
    #pragma mark - Public
    
    - (void)publicMethod {}
    
    #pragma mark - Private
    
    - (void)privateMethod {}
    
    #pragma mark - Protocol conformance
    #pragma mark - UITextFieldDelegate
    #pragma mark - UITableViewDataSource
    #pragma mark - UITableViewDelegate
    
    #pragma mark - NSCopying
    
    - (id)copyWithZone:(NSZone *)zone {}
    
    #pragma mark - NSObject
    
    - (NSString *)description {}
    
  • 注释: .h文件中必须要有注释,标明属性方法等的含义,.m文件中选择性适当注释业务逻辑。当需要注释时,注释应该用来解释这段特殊代码为什么要这样做。任何被使用的注释都必须保持最新或被删除。

  • 方法之间的间隔
    在方法签名中,应该在方法类型(-/+ 符号)之后有一个空格。在方法各个段之间应该也有一个空格(符合Apple的风格)。在参数之前应该包含一个具有描述性的关键字来描述参数。
    应该:
    - (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)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.

  • 在方法之间应该有且只有一行,这样有利于在视觉上更清晰和更易于组织。在方法内的空白应该分离功能,但通常都抽离出来成为一个新方法。

  • 缩进使用4个空格,确保在Xcode偏好设置来设置,确保代码对齐。

  • 方法大括号和其他大括号(if/else/switch/while 等.)总是在同一行语句打开但在新行中关闭
    应该:
    if (user.isHappy) {
    //Do something
    } else {
    //Do something else
    }
    不应该:
    if (user.isHappy)
    {
    //Do something
    }
    else {
    //Do something else
    }

  • 应该避免以冒号对齐的方式来调用方法。因为有时方法签名可能有3个以上的冒号和冒号对齐会使代码更加易读。请不要这样做,尽管冒号对齐的方法包含代码块,因为Xcode的对齐方式令它难以辨认。
    应该:
    // 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
    }];

变量###

  • 私有变量应该尽可能代替实例变量的使用。尽管使用实例变量是一种有效的方式,但更偏向于使用属性来保持代码一致性。
    应该:
    @interface RWTTutorial : NSObject
    @property (strong, nonatomic) NSString *tutorialName;
    @end
    不应该:
    @interface RWTTutorial : NSObject {
    NSString *tutorialName;
    }

字面值###

  • NSString, NSDictionary, NSArray, 和 NSNumber的字面值应该在创建这些类的不可变实例时被使用。请特别注意nil值不能传入NSArray和NSDictionary字面值,因为这样会导致crash。
    应该:
    NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
    NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
    NSNumber *shouldUseLiterals = @YES;
    NSNumber *buildingStreetNumber = @10018;
    不应该:
    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];

枚举类型###

  • 当使用enum时,推荐使用新的固定基本类型规格,因为它有更强的类型检查和代码补全。现在SDK有一个宏NS_ENUM()来帮助和鼓励你使用固定的基本类型。
    例如:
    typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
    RWTLeftMenuTopItemMain,
    RWTLeftMenuTopItemShows,
    RWTLeftMenuTopItemSchedule
    };
    或者显式地赋值:
    typedef NS_ENUM(NSInteger, RWTGlobalConstants) {
    RWTPinSizeMin = 1,
    RWTPinSizeMax = 5,
    RWTPinCountMin = 100,
    RWTPinCountMax = 500,
    };
    不应该:
    enum GlobalConstants {
    kMaxPinSize = 5,
    kMaxPinCount = 500,
    };

条件语句###

  • 只用一行代码,也应该使用大括号包围。一方面,可能发生在if语句里面一行代码被注释了,然后下一行代码不知不觉地成为if语句的一部分。另一方面,这种风格与其他条件语句的风格保持一致,所以更加容易阅读。
    应该:
    if (!error) {
    return success;
    }
    不应该:
    if (!error)
    return success;
    也不应该:
    if (!error) return success;

黄金路径###

  • 当使用条件语句编码时,不要嵌套if语句,多个返回语句也是OK。
    应该:
    - (void)someMethod {
    if (![someOther boolValue]) {
    return;
    }
    //Do something important
    }
    不应该:
    - (void)someMethod {
    if ([someOther boolValue]) {
    //Do something important
    }
    }

Xcode工程###

  • 物理文件应该与Xcode工程文件保持同步来避免文件扩张。任何Xcode分组的创建应该在文件系统的文件体现。代码不仅是根据类型来分组,而且还可以根据功能来分组,这样代码更加清晰。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容