1、条件表达式
- 1、当有条件过多、过长的时候需要换行,为了代码看起来整齐些
//good
if (condition1() &&
condition2() &&
condition3() &&
condition4()) {
// Do something
}
//bad
if (condition1() && condition2() && condition3() && condition4()) { // Do something }
- 2、在一个代码块里面有个可能的情况时善于使用 return 来结束异常的情况。
- (void)doHomework
{
if (self.hungry) {
return;
}
...
}
- 3、每个分支的实现都必须使用 {} 包含。
// bad
if (self.hungry) self.eat()
// good
if (self.hungry) {
self.eat()
}
- 4、条件判断的时候应该是变量在左,条件在右。
if ( currentCursor == 2 ) { //... }
- 5、switch 语句后面的每个分支都需要用大括号括起来。
2、类名
-
1、大写驼峰式命名。每个单词首字母大写。比如「申请记录控制器」
ApplyRecordsViewController
-
2、每个类型的命名以该类型结尾。
- ViewController:使用 ViewController 结尾。例子:ApplyRecordsViewController
- View:使用 View 结尾。例子:分界线:boundaryView
- NSArray:使用 s 结尾。比如商品分类数据源。categories
- UITableViewCell:使用 Cell 结尾。比如 MyProfileCell
- Protocol:使用 Delegate 或者 Datasource 结尾。比如 XQScanViewDelegate
- Tool:工具类
- 代理类:Delegate
- Service 类:Service
3、枚举
枚举的命名和类的命名相近。
typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
UIControlContentVerticalAlignmentCenter = 0,
UIControlContentVerticalAlignmentTop = 1,
UIControlContentVerticalAlignmentBottom = 2,
UIControlContentVerticalAlignmentFill = 3,
};
4、宏
- 1、全部大写,单词与单词之间用
_
连接。 - 2、以
K
开头。后面遵循大写驼峰命名。「不带参数」
#define HOME_PAGE_DID_SCROLL @"com.xq.home.page.tableview.did.scroll"
#define KHomePageDidScroll @"com.xq.home.page.tableview.did.scroll"
5、属性
书写规则,基本上就是 @property
之后空一格,括号,里面的 线程修饰词、内存修饰词、读写修饰词,空一格 类 对象名称
根据不同的场景选择合适的修饰符。
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, assign, readonly) BOOL loading;
@property (nonatomic, weak) id<#delegate#> delegate;
@property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);
6、私有变量
推荐以 _
开头,写在 .m 文件中。例如 NSString * _somePrivateVariable
7、代理方法
- 1、类的实例必须作为方法的参数之一。
- 2、对于一些连续的状态的,可以加一些 will(将要)、did(已经)
- 3、以类的名称开头
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
8、方法
- 1、方法与方法之间间隔一行
- 2、大量的方法尽量要以组的形式放在一起,比如生命周期函数、公有方法、私有方法、setter && getter、代理方法..
- 3、方法最后面的括号需要另起一行。遵循 Apple 的规范
- 4、对于其他场景的括号,括号不需要单独换行。比如 if 后面的括号。
- 5、如果方法参数过多过长,建议多行书写。用冒号进行对齐。
- 6、一个方法内的代码最好保持在50行以内,一般经验来看如果一个方法里面的代码行数过多,代码的阅读体验就很差(别问为什么,做过重构代码行数很长的人都有类似的心情)
- 7、一个函数只做一个事情,做到单一原则。所有的类、方法设计好后就可以类似搭积木一样实现一个系统。
- 8、对于有返回值的函数,且函数内有分支情况。确保每个分支都有返回值
- 9、函数如果有多个参数,外部传入的参数需要检验参数的非空、数据类型的合法性,参数错误做一些措施:立即返回、断言。
- 10、多个函数如果有逻辑重复的代码,建议将重复的部分抽取出来,成为独立的函数进行调用
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
- (void)doHomework:(NSString *)name
period:(NSInteger)second
score:(NSInteger)score;
- 11、方法如果有多个参数的情况下需要注意是否需要介词和连词。很多时候在不知道如何抉择测时候思考下苹果的一些 API 的方法命名。
//good
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
//bad
- (instancetype)initWithAge:(NSInteger)age andName:(NSString *)name;
- (void)tableView:(UITableView *)tableView :(NSIndexPath *)indexPath;
- 12、方法组之间也有个顺序问题。
- 1、在生命周期的方法里面,比如 viewDidLoad 里面只做界面的添加,而不是做界面的初始化
- 2、不要在除了getter之外的结构中设置view基本坐标、属性等。getter方法中不要添加比较重要重要的业务逻辑,重要的业务逻辑应该单独拿出来,放在对应的pragra mark 下,否则对于代码的阅读者来说,比较难以定位逻辑的入口位置。实际开发中遇到过多次这样的情况,焦头烂额的寻找关键逻辑入口处,纵里寻她千百度,结果它却躺在 getter方法中。
- 3、在viewDidAppear里面做Notification的监听之类的事情
- 4、每一个代理方法都对应上相应的协议,否则后期随着代码量的增加,很难找出某一代理方法对应的协议,不利于代码的可读性。
- 5、getter 和setter 方法写在代码的最后面。
- 6、UI布局可以说比较重要,也可以说不重要。重要是因为一个新手接手新项目,如果对布局还没有了解,业务逻辑便无从谈起;UI布局不重要是因为只要相关控件封装的足够好,页面UI布局通常会很简单;因为UI布局比较重要,所以笔者将它放在固定位置(setter&getter上面),因为UI布局通常比较简单,所以将其放在代码中比较靠后的位置。
#pragra mark - life cycle
#pragra mark - notification
#pragra mark - action
#pragra mark - UITableViewDelegate
.....总之这里是各种代理就对了
#pragra mark - UI
- (void)loadView;
#pragra mark - setter & getter
9、图片资源
- 1、单个文件的命名
文件资源的命名也需要一定的规范,形式为:功能模块名_类别_功能_状态@nx.png
Setting_Button_search_selected@2x.png、Setting_Button_search_selected@3x.png - 2、资源的文件夹命名 最好也参考 App 按照功能模块建立对应的实体文件夹目录,最后到对应的目录下添加相应的资源文件。
10、版本规范
采用 A.B.C 三位数字命名,比如:1.0.2,当有更新的情况下按照下面的依据
版本号 | 右说明对齐标题 | 示例 |
---|---|---|
A .b.c |
属于重大内容的更新 | 1.0.2 -> 2.0.0 |
a.B .c |
属于小部分内容的更新 | 1.0.2 -> 1.1.1 |
a.b.C
|
属于补丁更新 | 1.0.2 -> 1.0.3 |
11、用名字表达代码含义
一些比较有表达力的单词:
单词 | 可替代单词 |
---|---|
send | deliver、dispatch、announce、distribute、route |
find | search、extract、locate、recover |
start | launch、create、begin、open |
make | create、set up、build、generate、compose、add、new |
使用 i、j、k 作为循环迭代器的名字过于简单,user_i、member_i 这种名字会更有表达力。因为循环层次越多,代码越难理解,有表达力的迭代器名字可读性会更高。
为名字添加形容词等信息能让名字更具有表达力,但是名字也会变长。名字长短的准则是:作用域越大,名字越长。因此只有在短作用域才能使用一些简单名字。
12、名字不能带来歧义
起完名字要思考一下别人会对这个名字有何解读,会不会误解了原本想表达的含义。
- 布尔相关的命名加上 is、can、should、has 等前缀。
- 用 min、max 表示数量范围;
- 用 first、last 表示访问空间的包含范围;
- begin、end 表示访问空间的排除范围,即 end 不包含尾部
13、良好的代码风格
适当的空行和缩进。
排列整齐的注释:
int a = 1; // 注释
int b = 11; // 注释
int c = 111; // 注释
14、编写注释
阅读代码首先会注意到注释,如果注释没太大作用,那么就会浪费代码阅读的时间。那些能直接看出含义的代码不需要写注释,特别是并不需要为每个方法都加上注释,比如那些简单的 getter 和 setter 方法,为这些方法写注释反而让代码可读性更差。
不能因为有注释就随便起个名字,而是争取起个好名字而不写注释。
可以用注释来记录采用当前解决办法的思考过程,从而让读者更容易理解代码。
注释用来提醒一些特殊情况。
用 TODO 等做标记:
标记 | 用法 |
---|---|
TODO | 待做 |
FIXME | 待修复 |
HACK | 粗糙的解决方案 |
XXX | 危险!这里有重要的问题 |
15、版本号
我们都知道版本号是x.x.x这样的。关于它的命名规则,这里有篇简单的文章可以浏览一下版本号命名规范及原则,大致意思就是:
- 第一个数代表一些比较大的变动,比如全新的UI界面之类。
- 第二个数代表一些功能的新增或变化。
- 第三个数则代表一些bug的修复了,它往往很频繁。
网友评论