自用的 Object-C 代码规范

禅与 Object-C 编程艺术
GitHub

一、条件语句

1.1 使用 {} 将条件语句体包围

  • 推荐
if (error) {
    return @"错误";
}
  • 不推荐
if (error) 
{
    return @"错误";
}
if (error) 
    return @"错误";
if (error) return @"错误";

1.2 用变量与常量比较,不要倒装

  • 推荐
if (index == 20) {
    ...
}
  • 不推荐
if (20 == index) {
    ...
}

1.3 nil 和 BOOL 使用 ! 作为运算符

  • 推荐
if (!myObject) {
    ...
}
  • 不推荐
if (myObject == nil) {
    ...
}
if (nil == myObject) {
    ...
}

1.4 提前 return,不要嵌套 if 语句

  • 推荐
- (void)someMethod {
  if (![someOther boolValue]) {
      return;
  }

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

1.5 复杂条件拆分变量,不要写在 if 条件里

  • 推荐
BOOL nameContainsSwift  = [sessionName containsString:@"Swift"];
BOOL isCurrentYear      = [sessionDateCompontents year] == 2014;
BOOL isSwiftSession     = nameContainsSwift && isCurrentYear;

if (isSwiftSession) {
    // Do something very cool
}
  • 不推荐
if ([sessionName containsString:@"Swift"] && ([sessionDateCompontents year] == 2014)) {
    // Do something very cool
}

1.6 复杂三元运算符拆分变量,不要嵌套

  • 推荐
result = a > b ? x : y;
  • 不推荐
result = a > b ? x = c > d ? c : d : y;

1.7 方法通过参数返回 error 引用的,检查方法返回值,而不是检查 error

  • 推荐
NSError *error = nil;
BOOL result = [self trySomethingWithError:&error];
if (!result) {
    // Handle Error
}
  • 不推荐
NSError *error = nil;
[self trySomethingWithError:&error];
if (error) {
    // Handle Error
}

二、Case 语句

2.1 统一加上括号(*)

  • 推荐
switch (condition) {
        case 1: {
            // ...
            break;
        }
        case 2: {
            // ...
            break;
        }
        case 3:{
            // ...
            break;
        }
        default: {
            // ...
            break;
        }
    }
  • 不推荐
switch (condition) {
        case 1: 
            // ...
            break;
        case 2:
            // ...
            break;
        case 3:
            // ...
            break;
        default: 
            // ...
            break;
    }

三、命名

3.1 推荐使用长的、描述性的方法和变量名

  • 推荐
UIButton *settingsButton;
  • 不推荐
UIButton *setBut;

3.2 常量,驼峰命名,并加相关类作前缀

  • 推荐
static const NSTimeInterval ZOCSignInViewControllerFadeOutAnimationDuration = 0.4;
static NSString * const ZOCCacheControllerDidClearCacheNotification = @"ZOCCacheControllerDidClearCacheNotification";
static const CGFloat ZOCImageThumbnailHeight = 50.0f;
  • 不推荐
static const NSTimeInterval fadeOutTime = 0.4;
#define CompanyName @"Apple Inc."
#define magicNumber 42

3.3 方法,参数都带有描述性关键词,整个方法读起来像句子

  • 推荐
- (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.

3.4 字面值,使用快速创建的方式,不要写的复杂

  • 推荐
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @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 *buildingZIPCode = [NSNumber numberWithInteger:10018];

四、Class 类

4.1 类名使用三个大写字母作前缀

  • 推荐
ZOCNetworkClient
  • 不推荐
NetworkClient

4.2 Initializer 使用依赖注入

  • 推荐
@interface ZOCPerson
+ (instancetype)personWithName:(NSString *)name;
@end
  • 不推荐
@interface ZOCPerson
@property (nonatomic, copy) NSString *personName;
@end

这里需要补充 designated initializer (指定初始化)相关知识

4.3 属性,使用修饰定义,可选懒加载

  • 推荐
@property (nonatomic, assign) NSInteger page;
@property (nonatomic, assign) CGFloat amount;
@property (nonatomic, copy) NSString *name;

@property (nonatomic, copy) NSArray *list;// 需要用作可变数据使用时,必须是 copy(其他类似)
@property (nonatomic, strong) NSArray *list;

@property (nonatomic, strong) NSMutableArray *list;

默认属性 (atomic, readwrite, assign)
默认修饰 readwrite 不写,特殊需求时加入;
默认修饰 assign 虽然是默认,也统一写上;

五、Category 分类

5.1 方法名加小写前缀以及下划线

  • 推荐
@interface NSDate (ZOCTimeExtensions)
- (NSString *)zoc_timeAgoShort;
@end
  • 不推荐
@interface NSDate (ZOCTimeExtensions)
- (NSString *)timeAgoShort;
@end

六、Protocols 协议

任何在未来可复用的设计,无形当中可以提高代码质量,这也应该一直是程序员的追求。是否这样设计代码,就是大师和菜鸟的区别。

七、NSNotification 通知,通知名词定义成常量

  • 推荐
// Foo.h
extern NSString * const ZOCFooDidBecomeBarNotification
// Foo.m
NSString * const ZOCFooDidBecomeBarNotification = @"ZOCFooDidBecomeBarNotification";

八、美化代码

8.1 空格

  • 4个空格代替 Tab,Xcode 默认设置
  • 方法的大括号和其他的大括号(if/else/switch/while 等) 总是在同一行开始,在新起一行结束。

  • 推荐

if (user.isHappy) {
    //Do something
}
else {
    //Do something else
}
  • 不推荐
if (user.isHappy)
{
  //Do something
} else {
  //Do something else
}

8.2 换行:使用 Xcode 默认(*)

8.3 空行:分类之间空一行

代码分类:函数体,条件,case,等

九、代码组织

9.1 代码块

  • 代码块如果在闭合的圆括号内的话,会返回最后语句的值
  • 感觉是个骚操作,并不是很推荐使用;
NSURL *url = ({
    NSString *urlString = [NSString stringWithFormat:@"%@/%@", baseURLString, endpoint];
    [NSURL URLWithString:urlString];
});

9.2 Pragma

#pragma mark - Lifecycle



#pragma mark - Action



#pragma mark - Methods



#pragma mark - Delegate And DataSource



#pragma mark - Getter And Setter

9.3 自定义警告与错误

#warning [cz] <#descriptor#>

#error [cz] <#descriptor#>

9.4 文档

/**
title(一句话总结)

detail(详细说明)

 @param index <#index description#>
 @param length <#length description#>
 */

Xcode 10 快捷键【command + option + /】

十、其他自用

10.1 UI 类,统一使用完整名称,不要缩写

  • 推荐
    UILabel *nameLabel;
    UIButton *loginButton;
    UIImageView *avatarImageView;
    
    UIView *contentView;
    UIScrollView *detailScrollerView;
    
    UITableView *orderTableView;
    UITableViewCell *orderTableViewCell;
    
    // 这个特殊处理,省略 View(参考苹果官方的 UIAlertController,不然实在是太长了,因为要加模块-功能前缀)
    UIViewController *orderController;

除了 UIViewController 特殊处理,其余全部使用完整命名

  • 不推荐
    UILabel *nameLab;
    UIButton *loginBtn;
    UIImageView *avatarImgView;
    
    UIView *contentV;
    UIScrollView *detailScroller;
    
    UITableView *orderTable;
    UITableViewCell *orderCell;
    
    // 这个特殊处理,省略 View(参考苹果官方的 UIAlertController,不然实在是太长了,因为要加模块-功能前缀)
    UIViewController *orderVC;

10.2 数据类,按规定简写

  • 推荐
// 通用规则:可变类型,使用 M 后缀

// 常用的 4 个,使用缩写:Str、Arr、Dic、AttStr
    NSString *nameStr;
    NSMutableString *nameStrM;

    NSArray *nameArr;
    NSMutableArray *nameArrM;
    
    NSDictionary *nameDic;
    NSMutableDictionary *nameDicM;
    
    NSAttributedString *nameAttStr;
    NSMutableAttributedString *nameAttStrM;

// 以下不常用的或者其他的,统一使用完整名称,不缩写
    NSSet *nameSet;
    NSMutableSet *nameSetM;
        
    NSDate *nameDate;
    
    NSData *nameData;
    NSMutableData *nameDataM;