GB代码规范1.0

时间:2022-06-09
本文章向大家介绍GB代码规范1.0,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

GB代码规范

头文件#import的顺序(商量)

写法模板 #import <系统库> #import <第三方库> #import "其他类" 尽量按照先系统类 第三方类 自己写的类顺序导入 中间不能有空格

建议的写法

#import <UIKit/UIKit.h>
#import <Google/Analytics.h>
#import "GBOrderEmptyView.h"

不建议的写法

#import "GBOrderEmptyView.h"

#import <UIKit/UIKit.h>

#import <Google/Analytics.h>

@Class的写法

写法模板 @class class1,class2;

建议的写法

@class UIView,UIImage;

不建议的写法

@class UIPress;
@class UIPressesEvent;

@Interface的写法

写法模板 @interface 类名 : 父类 <协议1, 协议2> @interface和类名中间一个空格 类名后紧跟:之后空格加上父类协议之间用,空格分割

建议的写法

@interface AppDelegate : UIResponder <UIApplicationDelegate, UITableViewDataSource>

不建议的写法

@interface AppDelegate:UIResponder<UIApplicationDelegate,UITableViewDataSource>

@protocol的写法

写法的模板 @protocol 协议的名称 <协议1, 协议2> @potocol和协议的名称有空格 协议的名称和其他协议有空格 其他协议之间有空格

建议的写法

@protocol UIResponderStandardEditActions <NSObject>

不建议的写法

@protocol UIResponderStandardEditActions<NSObject>

@property的写法

@property(关键词, 关键词) 类 *变量名称; 关键词用,空格分割 类前后空格

正确写法

@property(strong, nonatomic) UIWindow *window;

不建议的写法

@property (strong, nonatomic) UIWindow * window;

@property关键词的使用

对象 strong 基本变量assign XIB控件 代理 weak 字符串和block使用 copy 对于一些弱引用对象使用weak 对于需要赋值内存对象 copy

h头文件方法写法

写法模板 @interface 方法的参数在一排显示 方法之间保留一行 第一个方法和@interface保留空行 最后一个方法和@end保留空行

建议的写法

@interface Text : NSObject

- (void)testFunction;

@end

错误写法

@interface Text : NSObject
- (void)testFunction;
@end

声明const的字符串

开头用k标识 推荐k+模板名字首字母大写+作用名称 防止和其他的重复 比如:CartViewModel类需要声明更新购物车列表的通知 kCVMNoticationUpdateCartList 如果是声明Cell的重用字符 k+cell的名称+identifier 比如: GBHomeItemTableViewCell的标识符 kGBHomeItemTableViewCellIdentifier

Const声明字符串位置

如果是需要声明在h里面让其他的类用到需要在h声明m实现

声明

UIKIT_EXTERN NSString *const kNoticationUpdateCartList;

实现

NSString *const kNoticationUpdateCartList = @"kNoticationUpdateCartList";

对于如果导入是UIKit类就使用UIKIT_EXTERN 如果是Founction使用关键词FOUNDATION_EXTERN

如果只在本类使用只用写实现 不用写声明。

方法尽量控制最多五十行

一个方法内部最多五十行 如果超过就精简代码 就分开方法写

方便之后进行热修复 代码重构

注释一定要写

自己管理的类一定注释属性用途 方法的用途 参数的说明

属性如果设置默认值 一定注明默认值是什么

如果方法内部存在逻辑判断 方法跳转 一定注释判断用法 方法跳转用法

除了初始化操作

其他声明变量 赋值 判断 应该注明注释用途

不允许外接修改的属性要设置readonly

大家平时设置属性默认是可读可写 但是这样容易对于别人造成误解 以为可以赋值

对于只能获取的属性 一定写readonly

头文件引入的其他类 要使用@class

头文件引入的类使用@class声明不实用#import引入

可以防止互相引入 编译失败 不容易查找的BUG

造成的缺点

m文件还要#import 其他类调用这个类属性也要#import对应的类

综合来说宁愿自己多操作 也要防止这种循环引入的BUG的出现

pragma mark的使用

对于属性的不同作用 比如设置颜色的 设置字体的 设置其他样式 的可以进行分组

对于方法的作用分类 比如添加功能 删除功能的

对于其他的代理方法 Get Set方法 Init初始化方法

BOOL类型属性的声明

属性set不要带is get要带is

@property(nonatomic, assign, getter=isUserLogin) BOOL userLogin;

方法命名的规范

不能用init set 开头进行命名

如果不是写初始化方法不要用init进行开头

如果不是属性的set方法不要用set作为方法的前缀

{}的写法

建议的写法

if(YES) {
  doing something
}

不建议的写法

if(YES)
{
  doing something
}

计算符号两边要有空格

比如 + - * / =等运算符左右有空格

建议的写法

x = 1 + 2;

不建议的写法

x=1+2;

控件命名的规范

对于命名一定不要简写 那篇很长的单词 但是一些单词就是简写的除外 比如WTO RMB

UILabel结尾加上Label;

UIImageView结尾记上ImageView

等等让其他的编程人员看名字就知道变量的用法 和属于什么控件

建议的写法

@property(nonatomic, strong) UILabel *userNameLabel;

不建议的写法

@property(nonatomic, strong) UILabel *name;

if判断里面的条件要提取出来

对于if里面很多的判断条件 要提取出来 方便之后进行断点测试

建议的写法

BOOL isTrue = 5 > 3;
if(isTrue) {
}

不建议的写法

if(5 > 3){
}

enum的定义

对于归属所在的enum 要写在对应的类

我们现在就全部enum放在一个文件 觉得和苹果的编码规范违背 并且分离代码有点麻烦

使用NS_ENUM进行定义

建议的写法

typedef NS_ENUM(NSUInteger, GBAppRunDeveloperMode) {
    GBAppRunDeveloperModeDebug,
    GBAppRunDeveloperModePreRelease,
    GBAppRunDeveloperModeRelease
};

不建议的写法

typedef enum {
    GBAppRunDeveloperModeDebug,
    GBAppRunDeveloperModePreRelease,
    GBAppRunDeveloperModeRelease
}GBAppRunDeveloperMode;

对于初始化一定要使用类对应的初始化方法

比如UIView的对应初始化方法为

- (instancetype)initWithFrame:(CGRect)frame

UIViewController对应的为

- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil

防止初始化用init new等没经过系统进行设置一些默认的属性 造成bug

对于声明NSString const要对适应对应的模块

比如系统的 NSNotificationName

typedef NSString *NSNotificationName NS_EXTENSIBLE_STRING_ENUM;

建议的写法

typedef NSString *NSStringConfigProjectName;
FOUNDATION_EXPORT NSStringConfigProjectName const kConfigProjectPluginDebugBaseUrlString;

不建议的写法

FOUNDATION_EXPORT NSString *const kConfigProjectPluginDebugBaseUrlString;

命名的一些推荐关键词

steup with cart buy等等待完善

对于#define宏命名

单词全部的大写 单词之间用_分割

建议的写法

#define NS_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios)

不建议的写法

#define NSAvailableIos(_ios) CF_AVAILABLE_IOS(_ios)

对象调用方法要留空格

建议的写法

[[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]

不建议的写法

[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]

对于只在m内部声明的const 需要添加static

这个我觉得可以不加 但是无法看到苹果的实现 所以不知道苹果的规范怎么写的

建议写法

static NSStringInitCheckManger const KGoogleServerTestKey = @""

不建议的写法

NSStringInitCheckManger const KGoogleServerTestKey = @""

对于局部的变量尽量的初始化

局部的变量要初始化 属性有默认的值 所以我们不必须对于属性进行初始化

我之前遇到的一个BUG就是int类型没有初始化给我默认Nan造成崩溃

建议的写法

int index = 0;

不建议的写法

int index;

对于一些对象判断是否赋值可以不进行初始化 但是对于一定不会为nil要进行初始化

变量名的规范

一定要使用驼峰的命名

建议的写法

UNUserNotificationCenter *unCenter = [UNUserNotificationCenter currentNotificationCenter];

不建议的写法

UNUserNotificationCenter *uncenter = [UNUserNotificationCenter currentNotificationCenter];

对于属性的赋值

不要直接调用set方法

建议的写法

unCenter.delegate = self;

不建议的写法

[unCenter setDelegate:self];

对于NS_OPTIONS类型多个值用|连接不能用+

建议的写法

UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound

不建议的写法

UNAuthorizationOptionAlert+UNAuthorizationOptionBadge+UNAuthorizationOptionSound

block的命名规范

之前研究过很多的第三方的命名 对于苹果官方的没找到

有CallBack结尾 Complete结尾 Block结尾 还有CompletionHandle结尾的

我看到苹果很多的结尾都是用CompletionHandle结尾

大部分命名是Block我们按照Block命名

建议的写法

typedef void(DidUpdateViewCompletionHandle)(void)

错误写法

typedef void(DidUpdateViewCallBack)

使用NSUserDefaults要先创建

因为我们用到NSUserDefaults无非是保存和读取 事先的创建一个对象 可以精简代码

当执行方法很多 用变量替换

建议的写法

NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault setDouble:CFAbsoluteTimeGetCurrent() forKey:@"AppStartTime"];

不建议的写法

[[NSUserDefaults standardUserDefaults] setDouble:CFAbsoluteTimeGetCurrent() forKey:@"AppStartTime"]

尽量少在initialize load方法做一些初始化的事情

影响程序的启动

建议的做法

- (void)viewDidLoad {
    [super viewDidLoad];
    [[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName : GBCOLOR(153, 153, 153, 1.0)} forState:UIControlStateNormal];
    [[UITabBarItem appearance] setTitleTextAttributes:                                                         @{NSForegroundColorAttributeName : GBCOLOR(255, 129, 55, 1.0)} forState:UIControlStateSelected];
 }

不建议的做法

+ (void)initialize {
    [[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName : GBCOLOR(153, 153, 153, 1.0)} forState:UIControlStateNormal];
    [[UITabBarItem appearance] setTitleTextAttributes:                                                         @{NSForegroundColorAttributeName : GBCOLOR(255, 129, 55, 1.0)} forState:UIControlStateSelected];
}

通知的移除

通知在dealloc要使用移除对象监听的方法

建议的写法

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

不建议的写法

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:name1 object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:name2 object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:name3 object:nil];
}

判断不要放在一行

判断放在一行也是可以的 但是我们还是要求正规一些 毕竟注明Apple的goto BUG

建议的写法

if (!self.startPagesListInfo) {
  return ;
}

不建议的写法

if (!self.startPagesListInfo) return ;

对于我们取值和存值的key要定义一下

定义一下key 方便我们使用 并且方便之后改名字

建议的写法

NSString startLoadString = @"startLoad";
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault objectForKey:startLoadString]
[userDefault setObject:@() forKey:startLoadString]

不建议的写法

NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
[userDefault objectForKey:@"startLoad"]
[userDefault setObject:@() forKey:@"startLoad"]

方法的参数连接不能有空格

建议的写法

- (BOOL)judgeStartLoadPageInTimeCurrentWithModel:(StartPageModel *)obj

不建议的写法

- (BOOL)judgeStartLoadPageInTimeCurrentWithModel : (StartPageModel *)obj;

对于block的循环引用使用weakify 和strongify

建议的写法

@weakify(self);
[@[] enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  @strongify(self);
}];

不建议的写法

__weak typeof(self) weakSelf = self;
[@[] enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    __strong typeof(weakSelf) strongSelf = weakSelf;
}];

布局和设置约束的方法选择

可以实现GBInitViewProtocol协议 执行对应的方法

建议的写法

#pragma mark - <GBInitViewProtocol>
- (void)gbInitView {
    self.backgroundColor = GBCOLOR_WHITE;
    [self addSubview:self.loadImageView];
}

- (void)gbAutoLayoutView {
    [self.loadImageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_equalTo(self).insets(UIEdgeInsetsZero);
    }];
}

有利于其他人很方便查找当前界面布局和添加试图的位置

属性要尽量使用懒加载

我们一个界面有很多控件 利用懒加载可以美化代码

所有的懒加载放在Getter的mark的下面

建议的写法

#pragma mark - getter
- (UIImageView *)loadImageView {
    if (!_loadImageView) {
        _loadImageView = [[UIImageView alloc] init];
        _loadImageView.image = [self imageWithScreen];
        _loadImageView.contentMode = UIViewContentModeScaleAspectFill;
        _loadImageView.userInteractionEnabled = YES;
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadImageTouchAction)];
        [_loadImageView addGestureRecognizer:tap];
    }
    return _loadImageView;
}

推荐的界面框架

所有界面的控件元素独立到另外的UIView

UIViewController只负责跳转界面

新建UIView负责界面的显示

VIewModel负责数据的请求和解析

APi负责请求

model负责后台数据解析

other 负责样式和其他处理

多使用字面量

字符串 @""

NSString *string = @"string";

NSNumber @()

NSNumber *number = @(1);

字典 @{}

NSDictionary *dictionary = @{@"name":@"123"};

数组 @[]

NSArray *array = @[@"321231",@"123"];

字典和数组的取值和存值

多用类型常量 少用#define

建议的写法

static const NSTimeInterval kAnimationDuration = 0.3;

不建议的写法

#define ANIMATION_DURATION 0.3

对于一些状态 选项的使用枚举

尽量少用根据数字判断状态少用字符串 数字判断状态

建议的写法

typedef NS_ENUM(NSUInteger, HomeViewState) {
    HomeViewStateNoData,
    HomeViewStateFailure,
    HomeViewStateItemList,
    HomeViewStateBannerList
};
if(state == HomeViewStateNoData){
  // 显示没数据
}else if(state == HomeViewStateFailure) {
  // 显示请求错误
}else if(state == HomeViewStateItemList) {
  // 显示商品的列表
}else if(state == HomeViewStateBannerList) {
  // 显示banner列表
}

不建议的写法

if(state == 0){
  // 显示没数据
}else if(state == 1) {
  // 显示请求错误
}else if(state == 2) {
  // 显示商品的列表
}else if(state == 3) {
  // 显示banner列表
}

多使用类族

比如我们需要创建一个类 有多个样式

typedef NS_ENUM(NSUInteger, ZHCustomViewStyle) {
    ZHCustomViewStyleRed,
    ZHCustomViewStyleWhite
};

@interface ZHCustomView : UIView

+ (instancetype)customWithStyle:(ZHCustomViewStyle)style;

@end
  
#import "ZHCustomView.h"
#import "ZHCustomRedView.h"
#import "ZHCustomWhiteView.h"

@implementation ZHCustomView

+ (instancetype)customWithStyle:(ZHCustomViewStyle)style {
    switch (style) {
        case ZHCustomViewStyleRed: {
            return [[ZHCustomRedView alloc] initWithFrame:CGRectZero];
        }
            break;
        case ZHCustomViewStyleWhite:{
            return [[ZHCustomWhiteView alloc] initWithFrame:CGRectZero];
        }
            break;
        default:
            break;
    }
}

@end

ZHCustomRedView

#import "ZHCustomView.h"

@interface ZHCustomRedView : ZHCustomView

@end

#import "ZHCustomRedView.h"

@implementation ZHCustomRedView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor redColor];
    }
    return self;
}

@end

ZHCustomWhiteView

#import "ZHCustomView.h"

@interface ZHCustomWhiteView : ZHCustomView

@end

#import "ZHCustomWhiteView.h"

@implementation ZHCustomWhiteView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor whiteColor];
    }
    return self;
}

@end

类名加上前缀避免冲突

因为团队的合作 可能会出现大家想到一样的名字或者添加第三方库引入和第三方库名字一样

尽量加上前缀。

如果只针对工程就使用工程的缩写

比如自己个人的第三方库就加上自己名字或者昵称的缩写

建议的写法

@interface GBHomeViewController : NSObject

不建议的写法

@interface HomeViewController : NSObject

提供全能的初始化方法

对于初始化参数有很多 但是不是一定全部使用的可以提供多个初始化方法

建议的写法

- (instancetype)initWithFrame:(CGRect)frame;
- (instancetype)initWithPerson:(GBPersonModel *)person;
- (instancetype)initWithFrame:(CGRect)frame person:(GBPersonModel *)person;

不建议的写法

- (instancetype)initWithFrame:(CGRect)frame person:(GBPersonModel *)person;

实现Description方便调试

这个不推荐自己手写 可以使用Xcode插件自动生成 属性越多会加重手写代码的长度

尽可能使用不可变的对象

对于OC存在很多可变的对象 比如NSMutableString NSMutableArray NSMutableDictionary等等

对于一些不允许改变的直接使用不可变对象

可以节省对象开支 还可以防止别人修改数据造成bug

建议的写法

NSArray *sexList = @[@"男",@"女"];

不建议的写法

NSMutableArray *sexList = [NSMutableArray arrayWithArray:@[@"男",@"女"]]

如果建议的使用Block和代理

我觉得代理可以用在写控件需要数据源赋值 和一些事件回调的时候使用

我查阅了苹果的block基本上都是执行一个时间 需要异步回调就使用block

如果没有主动执行动作 而是监听异步的回调 建议用代理

建议的写法

TestName *name = [[TestName alloc] init];
name.delegate = self;
[name searchText:text completionHandle:^(BOOL isExit) {
  
};

- (void)name:(TestName)name resultTextHaveChanged:(NSString *)text {
  
}

不建议的写法

TestName *name = [[TestName alloc] init];
[name searchText:text completionHandle:^(BOOL isExit) {
  
};
name.resultTextHaveChanged = ^(NSString *text) {
  
};

记得Dealloc记得释放

记得在Dealloc释放注册的通知和KVO的监听

不释放容易造成内存释放崩溃

养成习惯把按照方法功能到分类里面

对于一些有按照功能类型的方法划分在一个分类里面 分类和之前类写在同一个文件

建议的写法

@interface GBPerson : NSObject
@end
  
@interface GBPerson (Friend)
// 朋友
- (void)addFriend:(GBPenson *)friend;
- (void)deleteFriend:(GBPenson *)friend;
@end
@interface GBPerson (Play)
  // 娱乐
- (void)playSound;
- (void)playGame;
@end

不建议的写法

@interface GBPerson : NSObject

// 朋友
- (void)addFriend:(GBPenson *)friend;
- (void)deleteFriend:(GBPenson *)friend;

// 娱乐
- (void)playSound;
- (void)playGame;

为第三方类添加分类添加前缀

比如为系统UIView添加分类Add的添加前缀

建议的写法

@interface UIView (GB_Add) 
- (void)gb_addCustomView:(CustomView *)customView;
@end

不建议的写法

@interface UIView (Add)
- (void)addCustomView:(CustomView *)customView;
@end

尽量少在分类里面使用属性

假设我们分类有一个只读的字段 我们可以不使用属性 可以使用方法

建议的写法

@interface UIView (Add)
- (NSArray *)customViews;
@end
  
@implementation UIView (Add) 
- (NSArray *)customViews {
  return @[customView1,customView2];
}
@end

不建议的写法

@interface UIView (Add)
@property(nonatomic, strong, readonly) NSArray *customViews;
@end
  
@implementation UIView (Add) 
- (NSArray *)customViews {
  return @[customView1,customView2];
}
@end

非要在自己类的分类添加读写的属性 可以用语法糖

可以利用主类的私有变量

建议的写法

@interface ZHCustomView : UIView

@end
@interface ZHCustomView (Add)

@property(nonatomic, copy) NSString *name;

@end
#import "ZHCustomView.h"
@implementation ZHCustomView {
    NSString *_name;
}
@end

@implementation ZHCustomView (Add)

- (void)setName:(NSString *)name {
    _name = name;
}
- (NSString *)name {
    return _name;
}

@end

不建议的写法

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
    return objc_getAssociatedObject(self, "name");
}

对于给第三方和系统的类非要添加属性 可以使用runtime。

对于一些自己不确定的可以使用try catch

对于不知道后台返回什么类型的 可以使用try catch

建议的写法

int index = 0;
@try {
  NSArray *array = obj[@"list"];
  index = [array.firstObject intValue];
}
@catch {}

因为OC是运行时语法 可能array不一定是NSArray类型的

不建议的写法

int index = 0;
NSArray *array = obj[@"list"];
if(array.count > 0) {
  index = [array.firstObject intValue];
}

如果后台返回list为字段 这段代码就崩溃了 可以使用try catch也可以用Model库 或者自己添加判断

使用dispatch_once来创建单例

建议的写法

+ (instancetype)sharedInstance {
    static ZHCustomView* instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [ZHCustomView new];
    });

    return instance;
}

不建议的写法

+ (instancetype)sharedInstance {
    static ZHCustomView* instance = nil;
    if(!instance) {
      instance = [[ZHCustomView alloc] initWithFrame:CGRectZero];
    }
    return instance;
}

便利的写法

如果只需要便利数组和字典的写法用for in

建议的写法

for(NSString *name in names) {
  //
}

不建议的写法

for(int i = 0; i < names.lenght ; i ++) {
  NSString *name = names[i];
}

需要便利字典和数组的内容 并且需要索引用enumerator

建议的写法

[names enumerateObjectsUsingBlock:^(NSString * _Nonnull name, NSUInteger idx, BOOL * _Nonnull stop) {

}];

不建议的写法

for(int i = 0; i < names.lenght ; i ++) {
  NSString *name = names[i];
}

如果想进行缓存使用NSCache不要使用NSDictionary进行缓存

建议的写法

NSCache *cache = [[NSCache alloc] init];
[cache setObject:object forKey:key];

不建议的写法

NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
[dictionary setObject:object forKey:key];

尤达表达式

推荐:

if ([myValue isEqual:@42]) { ...

不推荐:

if ([@42 isEqual:myValue]) { ...

nil 和 BOOL 检查

推荐

if(name) {
  
}
if (isMyFriend) {
  
}

不建议的写法

if(name != nil) {
  
}
if(isMyFriend == YES) {
  
}

黄金大道

建议的写法

if(name.lenght <= 0) {
  return;
}
if(![name isEqualToString:@"zhanghang"]) {
  return;
}
.....

不建议的写法

if(name.lenght > 0) {
  if([name isEqualToString:@"zhanghang"]) {
    ....
  }
}

复杂的表达式

建议的写法

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
}

三元运算符

推荐:

result = a > b ? x : y;

不推荐:

result = a > b ? x = c > d ? c : d : y;

当三元运算符的第二个参数(if 分支)返回和条件语句中已经检查的对象一样的对象的时候,下面的表达方式更灵巧:

推荐:

result = object ? : [self createObject];

不推荐:

result = object ? object : [self createObject];

错误处理

有些方法通通过参数返回 error 的引用,使用这样的方法时应当检查方法的返回值,而非 error 的引用。

推荐:

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

此外,一些苹果的 API 在成功的情况下会对 error 参数(如果它非 NULL)写入垃圾值(garbage values),所以如果检查 error 的值可能导致错误 (甚至崩溃)。

数组和字典最好指定元素的类型

建议的写法

NSArray<NSString *> *names = [NSArray array];

不建议的写法

NSArray *names = [NSArray array];

数组和字典的元素垂直写

建议的写法

NSArray *array = @[
                    @"a",
                    @"b",
                    @"b"
                    ];
NSDictionary *dictionary = @{
                            @"a":@"",
                            @"b":@"",
                            @"c":@""
                            };

不建议写法

NSArray *array = @[@"a",@"b",@"b"];
NSDictionary *dictionary = @{@"a":@"",@"b":@"",@"c":@""};