前言
虽说我们编写的代码最终都会编译成机器码供操作系统运行,在运行我们的代码只要不出现异常就好;那为什么还会存在软件设计架构这个话题呢?其实际上无外乎涉及到以下几个方面
- 代码首先是要人来阅读的,如果你的代码没有一点架构、规范、注释等等,那么阅读起来就非常困难
- 不好的代码,后期去修改不仅费时费力,而且还很容易产生bug
- 我们不能保证我们写的代码没有任何问题,如果出现问题,一个好的架构下的代码会非常容易定位到问题所在
代码块标记
善用- pragma mark
- pragma mark
标记是为了便于查找和导航代码,也不要过分的使用这个标记,一般情况下,我们将属性、方法、协议、私有方法等,分组即可,如:
#pragma mark - property
- (UILabel *)userNameLabel {
if (!_userNameLabel) {
_userNameLabel = [[UILabel alloc] init];
}
return _userNameLabel;
}
#pragma mark - method
- (void)requestData {
// do something
}
#pragma mark - UITableView delegate
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 44;
}
不要去猜
不要让别人去猜你的代码要传入什么参数
,也不要让别人去猜你的代码返回了什么参数
一个很好的例子:
- (instancetype)initWithSelectedArray:(NSArray *)selectedArray;
对于以上代码,如果别人要调用这个方法只知道传入一个数组,但数组里面装的是什么数据?所以一个良好的习惯是善用泛型,如:
- (instancetype)initWithSelectedArray:(NSArray<ProductModel *> *)selectedArray;
以上代码一看就知道别人要调用需要传入一个ProductModel类型的数组,在返回值上面也是同样如此
善用注释
不要在意你多打几个字会浪费时间,一个好的注释能够快速的让人明白这个是做什么的
/// 显示日期选择器
/// @param startDate 选中的开始时间
/// @param endDate 选中的结束时间
/// @param callback 回调
+ (void)showTimePicker:(NSDate *_Nullable)startDate
endDate:(NSDate *_Nullable)endDate
cllback:(void(^)(NSDate *startDate, NSDate *endDate))callback;
不信任原则
我们通常在调用API时,对API返回的数据都会有一个不信任原则
,即返回来的数据我们在使用的时候都需要进行一个校验。
我们在写一些组件、方法同样也应当这么做。一个原则是传入过来的参数都需要进行一个合法校验,在必要时可根据场景使用return或者是throw出一个Exception
- (instancetype)initWithFrame:(CGRect)frame parentVC:(UIViewController *)parentVC childVCs:(NSArray *)childVCs {
if (self = [super initWithFrame:frame]) {
if (parentVC == nil) {
@throw [NSException exceptionWithName:@"PagingView" reason:@"SGPageContentScrollView 初始化方法中所在控制器必须设置" userInfo:nil];
}
self.parentViewController = parentVC;
if (childVCs == nil) {
@throw [NSException exceptionWithName:@"PagingView" reason:@"SGPageContentScrollView 初始化方法中子控制器必须设置" userInfo:nil];
}
self.childViewControllers = childVCs;
[self initialization];
[self setupSubviews];
}
return self;
}
或者
- (void)selectProduct:(Product *)model {
if (!model) {
return;
}
// do something
}
限制方法调用
使用NS_UNAVAILABLE
屏蔽掉不想让别人调用的方法
/**
Initialize with frame and title.
@param title Title of barButtonItem.
*/
-(nonnull instancetype)initWithTitle:(nullable NSString *)title NS_DESIGNATED_INITIALIZER;
/**
Unavailable. Please use initWithFrame:title: method
*/
-(nonnull instancetype)init NS_UNAVAILABLE;
不要忽略编译器的警告
在使用自动布局的时候一些布局上的警告,类型警告,废弃api的警告….等等
遵循好的版本号
一个好的版本号应当有三部分组成,主版本号
+次版本号
+Bug fix版本号
,
如15.7.1
、12.3.7.9
都是正常的写法;在发布版本时, 不兼容的版本应该主版本号加1
,日常功能特性版本就在次版本号加1
,bug修复就在Bug fix版本号加1
。
软件行业有很多包管理器都遵循这一规则,比如Cocoa Pods
、npm
包管理器等
break change
一个成熟的组件、库,在发布小版本迭代时,不应当有较大的改动,如果有,那么也应该有适当的兼容,比如
@property(nonatomic) CGRect contentStretch API_DEPRECATED("", ios(3.0, 6.0)) API_UNAVAILABLE(tvos);
这种写法,通常都会伴随一个很明显的注释
// please use -[UIImage resizableImageWithCapInsets:] to achieve the same effect.
虽然你调用是没问题的(会有一个警告),但这部分代码后期可能不复存在,应当尽早的更新到新版代码上 当如果有一个较大的版本时,主版本号都应当+1,表明是一个全新的大版本,这个时候可以把一些兼容性代码给移除掉
遵循代码规范
遵循一个好的团队代码规范和命名规范,能使得在review时事倍功半。
优秀的架构
无论是开发什么应用,成本和时间都是极为重要的,较少的开发时间意味着可以尽快的上线,较低的开发成本也能帮助公司节省资金,这就要求了我们的代码要具有很优秀的架构
本文首次发布于 孙忠良 Blog, 作者 [@sunzhongliang] , 转载请保留原文链接.