提升自己逼格的编程之美之代码规范
原文
1、头文件#import的顺序
写法模板
#import <系统库>
#import <第三方库>
#import “其他类”
尽量按照先系统类 第三方类 自己写的类顺序导入 中间不能有空格
建议的写法
1 #import <UIKit/UIKit.h> 2 #import <Google/Analytics.h> 3 #import "GBOrderEmptyView.h"
不建议的写法
1 #import "GBOrderEmptyView.h" 2 3 #import <UIKit/UIKit.h> 4 5 #import <Google/Analytics.h>
2、@Class的写法
写法模板
@class class1, class2;
建议的写法
1 @class UIView, UIImage;
不建议的写法
1 @class UIPress; 2 @class UIPressesEvent;
3、@Interface的写法
写法模板
@interface 类名 : 父类 <协议1, 协议2>
@interface和类名中间一个空格
类名后紧跟:之后空格加上父类协议之间用,空格分割
建议的写法
1 @interface AppDelegate : UIResponder <UIApplicationDelegate, UITableViewDataSource>
不建议的写法
1 @interface AppDelegate:UIResponder<UIApplicationDelegate,UITableViewDataSource>
4、@protocol的写法
写法的模板
@protocol 协议的名称 <协议1, 协议2>
@potocol和协议的名称有空格 协议的名称和其他协议有空格 其他协议之间有空格
建议的写法
1 @protocol UIResponderStandardEditActions <NSObject>
不建议的写法
1 @protocol UIResponderStandardEditActions<NSObject>
5、@property的写法
@property (关键词, 关键词) 类 *变量名称;
关键词用,空格分割 类前后空格
正确写法
1 @property (strong, nonatomic) UIWindow *window;
不建议的写法
1 @property(strong, nonatomic) UIWindow * window;
6、@property关键词的使用
对象 strong
基本变量assign
XIB控件 代理 weak
字符串和block使用 copy
对于一些弱引用对象使用weak
对于需要赋值内存对象 copy
7、h头文件方法写法
写法模板
@interface
方法的参数在一排显示
方法之间保留一行
第一个方法和@interface保留空行
最后一个方法和@end保留空行
建议的写法
1 @interface Text : NSObject 2 3 - (void)testFunction; 4 5 @end
错误写法
1 @interface Text : NSObject 2 - (void)testFunction; 3 @end
8、声明const的字符串
开头用k标识
推荐k+模板名字首字母大写+作用名称 防止和其他的重复
比如:CartViewModel类需要声明更新购物车列表的通知
kCVMNoticationUpdateCartList
如果是声明Cell的重用字符
k+cell的名称+identifier
比如: GBHomeItemTableViewCell的标识符
kGBHomeItemTableViewCellIdentifier
Const声明字符串位置
如果是需要声明在h里面让其他的类用到需要在h声明m实现
声明
1 UIKIT_EXTERN NSString *const kNoticationUpdateCartList;
实现
1 NSString *const kNoticationUpdateCartList = @"kNoticationUpdateCartList";
对于如果导入是UIKit类就使用UIKIT_EXTERN 如果是Founction使用关键词FOUNDATION_EXTERN
如果只在本类使用只用写实现 不用写声明。
9、方法尽量控制最多五十行
一个方法内部最多五十行 如果超过就精简代码 就分开方法写
方便之后进行热修复 代码重构
10、注释一定要写
自己管理的类一定注释属性用途 方法的用途 参数的说明
属性如果设置默认值 一定注明默认值是什么
如果方法内部存在逻辑判断 方法跳转 一定注释判断用法 方法跳转用法
除了初始化操作
其他声明变量 赋值 判断 应该注明注释用途
注释的写法
Class类注释
1 /** 2 订单的cell 3 */ 4 @interface OrdersCell : UITableViewCell
property属性的注释
1 /** 2 显示状态 3 */ 4 @property (nonatomic,strong) UILabel *statusLabel;
方法的注释,如果有返回值 请加上return
1 /** 2 显示倒计时文本 3 4 @param timerLabel 倒计时文本 5 @param countTime 剩余时间 6 */ 7 -(void)timerLabel:(MZTimerLabel*)timerLabel finshedCountDownTimerWithTime:(NSTimeInterval)countTime { 8 9 10 }
局部变量和全局变量注释
1 BOOL _isOfflinePay; // 是否是离线支付
Block注释
1 /*! 2 验证输入的是否正确 3 4 @param inputText 输入的文本 5 @return 如果返回值存在就代表验证失败 否则就代表成功 6 */ 7 typedef NSString * (^ATFVValidateInputCorrectComplete)(NSString *inputText);
NSUM的注释
1 /*! 2 当前输入框的状态 3 4 - ATFVEditStateNormal: 默认 还没有输入任何的文字 5 - ATFVEditStateEditing: 正在进行输入 6 - ATFVEditStateEdited: 输入完毕 7 - ATFVEditStateEditedError: 输入完毕错误 8 - ATFVEditStateNoEdit: 只允许编辑 9 */ 10 typedef NS_ENUM(NSUInteger, ATFVEditState) { 11 ATFVEditStateNormal, 12 ATFVEditStateEditing, 13 ATFVEditStateEdited, 14 ATFVEditStateEditedError, 15 // ATFVEditStateNoEdit 16 };
不允许外接修改的属性要设置readonly
大家平时设置属性默认是可读可写 但是这样容易对于别人造成误解 以为可以赋值,对于只能获取的属性 一定写readonly
正确的写法
1 @property (nonatomic, copy, readonly) NSString *name;
错误的写法
1 @property (nonatomic, copy) NSString *name;
11、头文件引入的其他类 要使用@class
头文件引入的类使用@class声明不实用#import引入
可以防止互相引入 编译失败 不容易查找的BUG
造成的缺点
m文件还要#import 其他类调用这个类属性也要#import对应的类
综合来说宁愿自己多操作 也要防止这种循环引入的BUG的出现
建议的写法
1 @class GBHomeViewController;
不建议写法
1 #import "GBHomeViewController.h"
12、pragma mark的使用
对于属性的不同作用 比如设置颜色的 设置字体的 设置其他样式 的可以进行分组
对于方法的作用分类 比如添加功能 删除功能的
对于其他的代理方法 Get Set方法 Init初始化方法
建议的写法
1 #pragma mark - Init 2 3 #pragma mark - Request 4 5 #pragma mark - Delegate 6 7 #pragma mark - DataSource 8 9 #pragma mark - Setter 10 11 #pragma mark - Getter
13、属性set不要带is get要带isBOOL类型属性的声明
建议写法
1 @property(nonatomic, assign, getter=isUserLogin) BOOL userLogin;
不建议写法
1 @property(nonatomic, assign) BOOL userLogin;
14、方法命名的规范
不能用init set 开头进行命名
如果不是写初始化方法不要用init进行开头
如果不是属性的set方法不要用set作为方法的前缀
15、{}的写法
建议的写法
1 if(YES) { 2 doing something 3 }
不建议的写法
1 if(YES) 2 { 3 doing something 4 }
16、计算符号两边要有空格
比如 + - * / =等运算符左右有空格
建议的写法
1 x = 1 + 2;
不建议的写法
1 x=1+2;
17、控件命名的规范
对于命名一定不要简写 那篇很长的单词 但是一些单词就是简写的除外 比如WTO RMB
UILabel结尾加上Label;
UIImageView结尾记上ImageView
等等让其他的编程人员看名字就知道变量的用法 和属于什么控件
建议的写法
1 @property (nonatomic, strong) UILabel *userNameLabel;
不建议的写法
1 @property (nonatomic, strong) UILabel *name;
18、对于if里面很多的判断条件 要提取出来 方便之后进行断点测试
建议的写法
1 BOOL isTrue = 5 > 3; 2 if(isTrue) { 3 }
不建议的写法
1 if(5 > 3){ 2 }
19、enum的定义
对于归属所在的enum 要写在对应的类
我们现在就全部enum放在一个文件 觉得和苹果的编码规范违背 并且分离代码有点麻烦
使用NS_ENUM进行定义
建议的写法
1 typedef NS_ENUM(NSUInteger, GBAppRunDeveloperMode) { 2 GBAppRunDeveloperModeDebug, 3 GBAppRunDeveloperModePreRelease, 4 GBAppRunDeveloperModeRelease 5 };
不建议的写法
1 typedef enum { 2 GBAppRunDeveloperModeDebug, 3 GBAppRunDeveloperModePreRelease, 4 GBAppRunDeveloperModeRelease 5 }GBAppRunDeveloperMode;
20、对于初始化一定要使用类对应的初始化方法
防止初始化用init new等没经过系统进行设置一些默认的属性 造成bug
比如UIView的对应初始化方法为
1 - (instancetype)initWithFrame:(CGRect)frame
UIViewController对应的为
1 - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil
21、对于声明NSString const要对适应对应的模块
比如系统的 NSNotificationName
1 typedef NSString *NSNotificationName NS_EXTENSIBLE_STRING_ENUM;
建议的写法
1 typedef NSString *NSStringConfigProjectName; 2 FOUNDATION_EXPORT NSStringConfigProjectName const kConfigProjectPluginDebugBaseUrlString;
不建议的写法
1 FOUNDATION_EXPORT NSString *const kConfigProjectPluginDebugBaseUrlString;
22、单词全部的大写 单词之间用_分割对于#define宏命名
建议的写法
1 #define NS_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios)
不建议的写法
1 #define NSAvailableIos(_ios) CF_AVAILABLE_IOS(_ios)
23、对象调用方法要留空格
建议的写法
1 [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
不建议的写法
1 [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]
24、对于只在m内部声明的const 需要添加static
这个我觉得可以不加 但是无法看到苹果的实现 所以不知道苹果的规范怎么写的
建议写法
static NSStringInitCheckManger const KGoogleServerTestKey = @""
不建议的写法
1 NSStringInitCheckManger const KGoogleServerTestKey = @""
25、对于局部的变量尽量的初始化
局部的变量要初始化 属性有默认的值 所以我们不必须对于属性进行初始化,对于一些对象判断是否赋值可以不进行初始化 但是对于一定不会为nil要进行初始化
我之前遇到的一个BUG就是int类型没有初始化给我默认Nan造成崩溃
建议的写法
1 int index = 0;
不建议的写法
1 int index;
26、变量名的规范
一定要使用驼峰的命名
建议的写法
1 UNUserNotificationCenter *unCenter = [UNUserNotificationCenter currentNotificationCenter];
不建议的写法
1 UNUserNotificationCenter *uncenter = [UNUserNotificationCenter currentNotificationCenter];
27、对于属性的赋值
不要直接调用set方法
建议的写法
1 unCenter.delegate = self;
不建议的写法
1 [unCenter setDelegate:self];
28、对于NS_OPTIONS类型多个值用|连接不能用+
建议的写法
1 UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound
不建议的写法
1 UNAuthorizationOptionAlert+UNAuthorizationOptionBadge+UNAuthorizationOptionSound
29、block的命名规范
之前研究过很多的第三方的命名 对于苹果官方的没找到
有CallBack结尾 Complete结尾 Block结尾 还有CompletionHandle结尾的
我看到苹果很多的结尾都是用CompletionHandle结尾
大部分命名是Block我们按照Block命名
建议的写法
1 typedef void(DidUpdateViewCompletionHandle)(void)
错误写法
1 typedef void(DidUpdateViewCallBack)
30、使用NSUserDefaults要先创建
因为我们用到NSUserDefaults无非是保存和读取 事先的创建一个对象 可以精简代码
当执行方法很多 用变量替换
建议的写法
1 NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; 2 [userDefault setDouble:CFAbsoluteTimeGetCurrent() forKey:@"AppStartTime"];
不建议的写法
1 [[NSUserDefaults standardUserDefaults] setDouble:CFAbsoluteTimeGetCurrent() forKey:@"AppStartTime"]
31、尽量少在initialize load方法做一些初始化的事情
影响程序的启动
建议的做法
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 [[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName : GBCOLOR(153, 153, 153, 1.0)} forState:UIControlStateNormal]; 4 [[UITabBarItem appearance] setTitleTextAttributes: @{NSForegroundColorAttributeName : GBCOLOR(255, 129, 55, 1.0)} forState:UIControlStateSelected]; 5 }
不建议的做法
1 + (void)initialize { 2 [[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName : GBCOLOR(153, 153, 153, 1.0)} forState:UIControlStateNormal]; 3 [[UITabBarItem appearance] setTitleTextAttributes: @{NSForegroundColorAttributeName : GBCOLOR(255, 129, 55, 1.0)} forState:UIControlStateSelected]; 4 }
32、通知的移除
通知在dealloc要使用移除对象监听的方法
建议的写法
1 - (void)dealloc { 2 [[NSNotificationCenter defaultCenter] removeObserver:self]; 3 }
不建议的写法
1 - (void)dealloc { 2 [[NSNotificationCenter defaultCenter] removeObserver:self name:name1 object:nil]; 3 [[NSNotificationCenter defaultCenter] removeObserver:self name:name2 object:nil]; 4 [[NSNotificationCenter defaultCenter] removeObserver:self name:name3 object:nil]; 5 }
33、判断不要放在一行
判断放在一行也是可以的 但是我们还是要求正规一些 毕竟注明Apple的goto BUG
建议的写法
1 if (!self.startPagesListInfo) { 2 return ; 3 }
不建议的写法
1 if (!self.startPagesListInfo) return ;
34、对于我们取值和存值的key要定义一下
定义一下key 方便我们使用 并且方便之后改名字
建议的写法
1 NSString startLoadString = @"startLoad"; 2 NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; 3 [userDefault objectForKey:startLoadString] 4 [userDefault setObject:@() forKey:startLoadString]
不建议的写法
1 NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; 2 [userDefault objectForKey:@"startLoad"] 3 [userDefault setObject:@() forKey:@"startLoad"]
35、方法的参数连接不能有空格
建议的写法
1 - (BOOL)judgeStartLoadPageInTimeCurrentWithModel:(StartPageModel *)obj
不建议的写法
1 - (BOOL)judgeStartLoadPageInTimeCurrentWithModel : (StartPageModel *)obj;
36、对于block的循环引用使用weakify 和strongify
建议的写法
1 @weakify(self); 2 [@[] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 3 @strongify(self); 4 }];
不建议的写法
1 __weak typeof(self) weakSelf = self; 2 [@[] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 3 __strong typeof(weakSelf) strongSelf = weakSelf; 4 }];
37、布局和设置约束的方法选择
可以实现GBInitViewProtocol协议 执行对应的方法
有利于其他人很方便查找当前界面布局和添加试图的位置
建议的写法
1 #pragma mark - <GBInitViewProtocol> 2 - (void)gbInitView { 3 self.backgroundColor = GBCOLOR_WHITE; 4 [self addSubview:self.loadImageView]; 5 } 6 7 - (void)gbAutoLayoutView { 8 [self.loadImageView mas_makeConstraints:^(MASConstraintMaker *make) { 9 make.edges.mas_equalTo(self).insets(UIEdgeInsetsZero); 10 }]; 11 }
38、属性要尽量使用懒加载
我们一个界面有很多控件 利用懒加载可以美化代码
所有的懒加载放在Getter的mark的下面
建议的写法
1 #pragma mark - getter 2 - (UIImageView *)loadImageView { 3 if (!_loadImageView) { 4 _loadImageView = [[UIImageView alloc] init]; 5 _loadImageView.image = [self imageWithScreen]; 6 _loadImageView.contentMode = UIViewContentModeScaleAspectFill; 7 _loadImageView.userInteractionEnabled = YES; 8 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(loadImageTouchAction)]; 9 [_loadImageView addGestureRecognizer:tap]; 10 } 11 return _loadImageView; 12 }
39、推荐的界面框架
所有界面的控件元素独立到另外的UIView
UIViewController只负责跳转界面
新建UIView负责界面的显示
VIewModel负责数据的请求和解析
APi负责请求
model负责后台数据解析
other 负责样式和其他处理
40、多使用字面量
字符串 @””
1 NSString *string = @"string";
NSNumber @()
1 NSNumber *number = @(1);
字典 @{}
1 NSDictionary *dictionary = @{@"name":@"123"};
数组 @[]
1 NSArray *array = @[@"321231", @"123"];
41、多用类型常量 少用#define
建议的写法
1 static const NSTimeInterval kAnimationDuration = 0.3;
不建议的写法
1 #define ANIMATION_DURATION 0.3
42、对于一些状态 选项的使用枚举
尽量少用根据数字判断状态少用字符串 数字判断状态
建议的写法
1 typedef NS_ENUM(NSUInteger, HomeViewState) { 2 HomeViewStateNoData, 3 HomeViewStateFailure, 4 HomeViewStateItemList, 5 HomeViewStateBannerList 6 }; 7 if(state == HomeViewStateNoData){ 8 // 显示没数据 9 }else if(state == HomeViewStateFailure) { 10 // 显示请求错误 11 }else if(state == HomeViewStateItemList) { 12 // 显示商品的列表 13 }else if(state == HomeViewStateBannerList) { 14 // 显示banner列表 15 }
不建议的写法
1 if(state == 0){ 2 // 显示没数据 3 }else if(state == 1) { 4 // 显示请求错误 5 }else if(state == 2) { 6 // 显示商品的列表 7 }else if(state == 3) { 8 // 显示banner列表 9 }
43、多使用类族
比如我们需要创建一个类 有多个样式
1 typedef NS_ENUM(NSUInteger, ZHCustomViewStyle) { 2 ZHCustomViewStyleRed, 3 ZHCustomViewStyleWhite 4 }; 5 6 @interface ZHCustomView : UIView 7 8 + (instancetype)customWithStyle:(ZHCustomViewStyle)style; 9 10 @end 11 12 #import "ZHCustomView.h" 13 #import "ZHCustomRedView.h" 14 #import "ZHCustomWhiteView.h" 15 16 @implementation ZHCustomView 17 18 + (instancetype)customWithStyle:(ZHCustomViewStyle)style { 19 switch (style) { 20 case ZHCustomViewStyleRed: { 21 return [[ZHCustomRedView alloc] initWithFrame:CGRectZero]; 22 } 23 break; 24 case ZHCustomViewStyleWhite:{ 25 return [[ZHCustomWhiteView alloc] initWithFrame:CGRectZero]; 26 } 27 break; 28 default: 29 break; 30 } 31 } 32 33 @end
ZHCustomRedView
1 #import "ZHCustomView.h" 2 3 @interface ZHCustomRedView : ZHCustomView 4 5 @end 6 7 #import "ZHCustomRedView.h" 8 9 @implementation ZHCustomRedView 10 11 - (instancetype)initWithFrame:(CGRect)frame { 12 if (self = [super initWithFrame:frame]) { 13 self.backgroundColor = [UIColor redColor]; 14 } 15 return self; 16 } 17 18 @end
ZHCustomWhiteView
1 #import "ZHCustomView.h" 2 3 @interface ZHCustomWhiteView : ZHCustomView 4 5 @end 6 7 #import "ZHCustomWhiteView.h" 8 9 @implementation ZHCustomWhiteView 10 11 - (instancetype)initWithFrame:(CGRect)frame { 12 if (self = [super initWithFrame:frame]) { 13 self.backgroundColor = [UIColor whiteColor]; 14 } 15 return self; 16 } 17 18 @end
44、类名加上前缀避免冲突
因为团队的合作 可能会出现大家想到一样的名字或者添加第三方库引入和第三方库名字一样,尽量加上前缀。
如果只针对工程就使用工程的缩写
比如自己个人的第三方库就加上自己名字或者昵称的缩写
建议的写法
1 @interface GBHomeViewController : NSObject
不建议的写法
1 @interface HomeViewController : NSObject
45、提供全能的初始化方法
对于初始化参数有很多 但是不是一定全部使用的可以提供多个初始化方法
建议的写法
1 - (instancetype)initWithFrame:(CGRect)frame; 2 - (instancetype)initWithPerson:(GBPersonModel *)person; 3 - (instancetype)initWithFrame:(CGRect)frame person:(GBPersonModel *)person;
不建议的写法
1 - (instancetype)initWithFrame:(CGRect)frame person:(GBPersonModel *)person;
46、实现Description方便调试
这个不推荐自己手写 可以使用Xcode插件自动生成 属性越多会加重手写代码的长度
47、尽可能使用不可变的对象
对于OC存在很多可变的对象 比如NSMutableString NSMutableArray NSMutableDictionary等等
对于一些不允许改变的直接使用不可变对象
可以节省对象开支 还可以防止别人修改数据造成bug
建议的写法
1 NSArray *sexList = @[@"男", @"女"];
不建议的写法
1 NSMutableArray *sexList = [NSMutableArray arrayWithArray:@[@"男", @"女"]]
48、如果建议的使用Block和代理
我觉得代理可以用在写控件需要数据源赋值 和一些事件回调的时候使用
我查阅了苹果的block基本上都是执行一个时间 需要异步回调就使用block
如果没有主动执行动作 而是监听异步的回调 建议用代理
建议的写法
1 TestName *name = [[TestName alloc] init]; 2 name.delegate = self; 3 [name searchText:text completionHandle:^(BOOL isExit) { 4 5 }; 6 7 - (void)name:(TestName)name resultTextHaveChanged:(NSString *)text { 8 9 }
不建议的写法
1 TestName *name = [[TestName alloc] init]; 2 [name searchText:text completionHandle:^(BOOL isExit) { 3 4 }; 5 name.resultTextHaveChanged = ^(NSString *text) { 6 7 };
49、记得Dealloc记得释放
记得在Dealloc释放注册的通知和KVO的监听
不释放容易造成内存释放崩溃
50、养成习惯把按照方法功能到分类里面
对于一些有按照功能类型的方法划分在一个分类里面 分类和之前类写在同一个文件
建议的写法
1 @interface GBPerson : NSObject 2 @end 3 4 @interface GBPerson (Friend) 5 // 朋友 6 - (void)addFriend:(GBPenson *)friend; 7 - (void)deleteFriend:(GBPenson *)friend; 8 @end 9 @interface GBPerson (Play) 10 // 娱乐 11 - (void)playSound; 12 - (void)playGame; 13 @end
不建议的写法
1 @interface GBPerson : NSObject 2 3 // 朋友 4 - (void)addFriend:(GBPenson *)friend; 5 - (void)deleteFriend:(GBPenson *)friend; 6 7 // 娱乐 8 - (void)playSound; 9 - (void)playGame;
51、为第三方类添加分类添加前缀
比如为系统UIView添加分类Add的添加前缀
建议的写法
1 @interface UIView (GB_Add) 2 - (void)gb_addCustomView:(CustomView *)customView; 3 @end
不建议的写法
1 @interface UIView (Add) 2 - (void)addCustomView:(CustomView *)customView; 3 @end
52、尽量少在分类里面使用属性
假设我们分类有一个只读的字段 我们可以不使用属性 可以使用方法
建议的写法
1 @interface UIView (Add) 2 - (NSArray *)customViews; 3 @end 4 5 @implementation UIView (Add) 6 - (NSArray *)customViews { 7 return @[customView1,customView2]; 8 } 9 @end
不建议的写法
1 @interface UIView (Add) 2 @property(nonatomic, strong, readonly) NSArray *customViews; 3 @end 4 5 @implementation UIView (Add) 6 - (NSArray *)customViews { 7 return @[customView1,customView2]; 8 } 9 @end
53、非要在自己类的分类添加读写的属性 可以用语法糖
可以利用主类的私有变量,
建议的写法
1 @interface ZHCustomView : UIView 2 3 @end 4 @interface ZHCustomView (Add) 5 6 @property(nonatomic, copy) NSString *name; 7 8 @end
1 #import "ZHCustomView.h" 2 @implementation ZHCustomView { 3 NSString *_name; 4 } 5 @end 6 7 @implementation ZHCustomView (Add) 8 9 - (void)setName:(NSString *)name { 10 _name = name; 11 } 12 - (NSString *)name { 13 return _name; 14 } 15 16 @end
不建议的写法
1 - (void)setName:(NSString *)name { 2 objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY_NONATOMIC); 3 } 4 - (NSString *)name { 5 return objc_getAssociatedObject(self, "name"); 6 }
对于给第三方和系统的类非要添加属性 可以使用runtime。
54、对于一些自己不确定的可以使用try catch
对于不知道后台返回什么类型的 可以使用try catch
建议的写法
1 int index = 0; 2 @try { 3 NSArray *array = obj[@"list"]; 4 index = [array.firstObject intValue]; 5 } 6 @catch {}
不建议的写法因为OC是运行时语法 可能array不一定是NSArray类型的
1 int index = 0; 2 NSArray *array = obj[@"list"]; 3 if(array.count > 0) { 4 index = [array.firstObject intValue]; 5 }
55、使用dispatch_once来创建单例
如果后台返回list为字段 这段代码就崩溃了 可以使用try catch也可以用Model库 或者自己添加判断
建议的写法
1 + (instancetype)sharedInstance { 2 static ZHCustomView* instance = nil; 3 static dispatch_once_t onceToken; 4 dispatch_once(&onceToken, ^{ 5 instance = [ZHCustomView new]; 6 }); 7 8 return instance; 9 }
不建议的写法
1 + (instancetype)sharedInstance { 2 static ZHCustomView* instance = nil; 3 if(!instance) { 4 instance = [[ZHCustomView alloc] initWithFrame:CGRectZero]; 5 } 6 return instance; 7 }
56、便利的写法
如果只需要便利数组和字典的写法用for in
建议的写法
1 for(NSString *name in names) { 2 // 3 }
不建议的写法
1 for(int i = 0; i < names.lenght ; i ++) { 2 NSString *name = names[i]; 3 }
需要便利字典和数组的内容 并且需要索引用enumerator
建议的写法
1 [names enumerateObjectsUsingBlock:^(NSString * _Nonnull name, NSUInteger idx, BOOL * _Nonnull stop) { 2 3 }];
不建议的写法
1 for(int i = 0; i < names.lenght ; i ++) { 2 NSString *name = names[i]; 3 }
57、如果想进行缓存使用NSCache不要使用NSDictionary进行缓存
建议的写法
1 NSCache *cache = [[NSCache alloc] init]; 2 [cache setObject:object forKey:key];
不建议的写法
1 NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; 2 [dictionary setObject:object forKey:key];
58、尤达表达式
推荐:
1 if ([myValue isEqual:@42]) { ...
不推荐:
1 if ([@42 isEqual:myValue]) { ...
59、nil 和 BOOL 检查
推荐
1 if(name) { 2 3 } 4 if (isMyFriend) { 5 6 }
不建议的写法
1 if(name != nil) { 2 3 } 4 if(isMyFriend == YES) { 5 6 }
60、黄金大道
建议的写法
1 if(name.lenght <= 0) { 2 return; 3 } 4 if(![name isEqualToString:@"zhanghang"]) { 5 return; 6 }
不建议的写法
1 if(name.lenght > 0) { 2 if([name isEqualToString:@"zhanghang"]) { 3 .... 4 } 5 } 6
61、复杂的表达式
建议的写法
1 BOOL nameContainsSwift = [sessionName containsString:@"Swift"]; 2 BOOL isCurrentYear = [sessionDateCompontents year] == 2014; 3 BOOL isSwiftSession = nameContainsSwift && isCurrentYear; 4 5 if (isSwiftSession) { 6 // Do something very cool 7 }
不建议的写法
1 if ([sessionName containsString:@"Swift"] && [sessionDateCompontents year] == 2014) { 2 // Do something very cool 3 }
62、三元运算符
推荐:
1 result = a > b ? x : y;
不推荐:
1 result = a > b ? x = c > d ? c : d : y;
当三元运算符的第二个参数(if 分支)返回和条件语句中已经检查的对象一样的对象的时候,下面的表达方式更灵巧:
推荐:
1 result = object ? : [self createObject];
不推荐:
1 result = object ? object : [self createObject];
63、错误处理
有些方法通通过参数返回 error 的引用,使用这样的方法时应当检查方法的返回值,而非 error 的引用。
推荐:
1 NSError *error = nil; 2 if (![self trySomethingWithError:&error]) { 3 // Handle Error 4 }
此外,一些苹果的 API 在成功的情况下会对 error 参数(如果它非 NULL)写入垃圾值(garbage values),所以如果检查 error 的值可能导致错误 (甚至崩溃)。
64、数组和字典最好指定元素的类型
建议的写法
1 NSArray<NSString *> *names = [NSArray array];
不建议的写法
1 NSArray *names = [NSArray array];
65、数组和字典的元素垂直写
建议的写法
1 NSArray *array = @[ 2 @"a", 3 @"b", 4 @"b" 5 ]; 6 NSDictionary *dictionary = @{ 7 @"a":@"", 8 @"b":@"", 9 @"c":@"" 10 };
不建议写法
1 NSArray *array = @[@"a",@"b",@"b"]; 2 NSDictionary *dictionary = @{@"a":@"",@"b":@"",@"c":@""};