iOS 编码规范
iOS 编码规范 1
目的 1
适用范围 2
1 命名 2
1.1 文件命名 2
1.2 类命名 3
1.3 方法命名 3
1.4 变量命名 3
1.4.1 一般变量 4
1.4.2 常量 4
2 注释 4
2.1 文件注释 5
2.2 声明注释 5
2.3 实现注释 5
3 代码格式 6
3.1 代码缩进 6
3.2 行长度 6
3.3 方法声明与定义 6
3.4 方法调用 7
3.5 @public 和 @private 8
3.6 异常 8
4 Cocoa模式 9
4.1 委托模式 9
4.2 MVC模式 9
目的
统一规范Xcode 编辑环境下Objective-C 的编码风格和标准。
适用范围
适用于所有用 Objective-C 语言开发的项目。
1 命名
命名规则对于维护代码来说是非常重要的。写纯Objective-C代码时,所有类,类别, 方法,以及变,我们推荐驼峰法,也是Objective-C社区的标准。如包括缩写,则缩写部分使用全大写的缩写 (Initialisms )形式。这遵守Apple的标准,比如URL、TIFF以及EXIF。
当写Objective-C++ 代码时,情况就不是那么单一了。许多项目需要实现带一些Objective-C代码的跨平台的C++ APIs或者连接后台的C++ 代码与前台的原生Cocoa代码.这会造成两种规范直接冲突。
我们的解决方法是根据方法/函数风格来决定。如果在 @implementation 块,就使用Objective-C的命名规则;如果在C++的方法实现块,就使用C++的命名规则。避免了实体变量和本地变量在一个函数内命名规则冲突的情况,而这种情况是对可读性的极大损害。
1.1 文件命名
文件名反映了它所包含的实现类的名字,遵从你所在项目的习惯。文件扩展名使用如下规则:
扩展名 描述
.h C/C++/Objective-C header file
.m Objective-C implementation file
.mm Objective-C++ implementation file
.cc Pure C++ implementation file
.c C implementation file
类别的文件名应该包含扩展类的名字,比如:GTMNSString+Utils.h or GTMNSTextView+Autocomplete.h。
1.2 类命名
类名(不包括类别和协议名)应该用大写开头的驼峰命名法。在应用级别的代码里,尽量不要使用带前缀的类名。每个类都有相同的前缀不能提高可读性。不过如果是编写多个应用间的共享代码,前缀就是可接受并推荐的做法了(比如:GTMSendMessage)。
类别命名应该以两三个字符的分类前缀作为一个项目或通用的公用部分。类别名应该包含类的扩展。举个例子,如果我们想要创建一个基于NSString 的类别用于解析,我们应该把类别放到名字是GTMNSString+Parsing.h 的文件里,而类别本身的名字则是GTMStringParsingAdditions (是的,我们明白这个类别和其文件名字不匹配,但这个文件可能还包括其他用于解析相关的类别)。类别的方法应该都使用一个前缀(比如gtm_myCategoryMethodOnAString),以防止Objective-C代码在单名空间里冲突。如果代码本来就不考虑共享或在不同的地址空间(address-space),方法命名规则就没必要恪守了。
1.3 方法命名
方法使用小写开头的驼峰法命名,每个参数都应该小写开头。方法名应该尽可能读起来像一句话,参数名就相对方法名的补充说明(比如convertPoing:fromRect: 或者 replaceCharactersInRange:withString: ),详见Apple’s Guide to Naming Methods。
存取(Accessor)方法应该一致的在“取(getting)”的时候直接用变量名而不是在签名加“get”,如下:
-
(id)getDelegate; // 不应该这样。
-
(id)delegate; // 应该这样。
不过这仅针对Objective-C代码,C++ 代码仍然遵循自己的代码规范。
1.4 变量命名
变量名使用小写开头的驼峰法,比如:myLovalVariable,myInstanceVariable_ 。
1.4.1 一般变量
使变量名尽量可以推测其用途属性具有描述性。别一心想着少打几个字母,让你的代码可以迅速被理解更加重要。比如:// AVOID
int w;
int nerr;
int nCompConns;
tix = [[NSMutableArray alloc] init];
obj = [someObject object];
p = [network port];
// GOOD
int numErrors;
int numCompletedConnections;
tickets = [[NSMutableArray alloc] init];
userInfo = [someObject object];
port = [network port];
1.4.2 常量
常量(预定义,枚举,局部常量等)使用小写k开头的驼峰法,比如kInvalidHandle,kWritePerm。
2 注释
尽管写起来很痛苦,但注释仍然是使代码保持可读性的极端重要的方式。下面的条款描述了你应该注释什么以及在哪里做注释。但是记住,即使注释是如此重要,最好的代码还是自说明式的。起一个有意义的名字比起一个晦涩的名字然后在用注释去解释它好的多。
当你写注释的时候,记住注释是写给读者,即下一个要理解你的代码并继续开发的人。“下一个”完全可能就是你自己。
同样,所有C++ 编码规范的条款仍然适用,只是增加了一些条款。
2.1 文件注释
每个文件的开头都是版权声明,接着是文件内容的描述。法律声明和作者栏每个文件都应该包含如下信息:
一份版权声明(比如 Copyright 2008 Google Inc .)。
许可版本,为项目选择合适的许可版本(比如Apache 2.0, BSD, LGPL, GPL)
如果你把别人写的文件做了相当大的改动,就把自己添加到作者栏去。这样别的开发者就方便联系这个文件的实际开发人员了。
2.2 声明注释
每个接口,类别,协议都必须伴随描述它的用途以及如何整合的注释。
// A delegate for NSApplication to handle notifications about app
// launch and shutdown. Owned by the main app controller.
@interface MyAppDelegate : NSObject {
…
}
@end
如果已经在文件的顶部写了接口的详细描述,你也可以简单的写如“见文件顶部的完整描述”,当然要有这些注释的顺序安排。
此外public接口的每个方法都应该添加关于函数,参数,返回值以及副作用的注释。
文档默认类都是同步的,如果类实例可以多线程访问,必须要加上额外的说明。
2.3 实现注释
使用竖线引用变量或符号,而不是用引号。这可以减少歧义,特别是当符号本身就是个常见的词时,可能使句子显得支离破碎,比如符号是“count”:
// Sometimes we need |count| to be less than zero.
或者是对于那些已经存在引号的情况。
// Remember to call |StringWithoutSpaces(“foo bar baz”)|
3 代码格式
3.1 代码缩进
仅使用空格,缩进两个。我们使用空格用于缩进,不要在编码时使用tab键,你应该设置你的编辑器将tab键转换成对应的空格。
3.2 行长度
代码中的每行文本不要超过80个字符的长度。函数的行数不超过50行。
尽管Objective-C正变得比C++ 更加繁冗,为了保持规范的互通性,我们还是决定保持80字符长度的限制。这比你想象中的更容易做到。
我们知道本条款是有争议的,但已有许多的代码已经遵从了本条款,即使只是保持一致性也是一个充足的理由。
你可以在Xcode里清楚地发现代码中的违规,设置 Xcode > Preferences > Text Editing > Show page guide. (之后就可以在代码编辑区域里看到一条指定字符长度的指示线了)。
3.3 方法声明与定义
留一个空格在 - 或 + 和返回类型之间,但参数列表里的参数之间不要留间隔。 方法应该写成这样:
- (void)doSomethingWithString:(NSString *)theString {
…
}
星号前的空格是可选的,你可以根据原来的代码风格自行决定。
如果参数过多,推荐每个参数各占一行。使用多行的情况下,以参数前的冒号用于对齐:
- (void)doSomethingWith:(GTMFoo *)theFoo
rect:(NSRect)theRect
interval:(float)theInterval {
…
}
当第一个关键字比其他的短时,后续行至少缩进四个空格。这样你可以让后续的关键字垂直对齐,而不是用冒号对齐:
- (void)short:(GTMFoo *)theFoo
longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval {
...
}
3.4 方法调用
方法调用的格式和方法声明时的格式时一致的,如果格式风格可选,遵从原有代码的风格。
调用应该将所有参数写在一行:
[myObject doFooWith:arg1 name:arg2 error:arg3];
或者每个参数一行,用冒号对齐:
(对齐效果如前说明)
[myObject doFooWith:arg1
name:arg2
error:arg3];
不要使用如下风格的写法:
[myObject doFooWith:arg1 name:arg2 // some lines with >1 arg
error:arg3];
[myObject doFooWith:arg1
name:arg2 error:arg3];
[myObject doFooWith:arg1
name:arg2 // aligning keywords instead of colons
error:arg3];
在声明和定义时,如果因为关键字长度使就算有四个空格在前仍然无法用冒号对齐,那么就让后续行缩进四个空格而不是冒号对齐:
[myObj short:arg1
longKeyword:arg2
evenLongerKeyword:arg3];
3.5 @public 和 @private
类似C++的public,protected,private:
@interface MyClass : NSObject {
@public
...
@private
...
}
@end
3.6 异常
每个异常标签的@ 和开括号({ )写在统一行,标签和开括号间隔一个空格,同样适用于@catch 语句。
如果你决定使用Objective-C的异常,那么就按如下格式。
@try {
foo();
}
@catch (NSException *ex) {
bar(ex);
}
@finally {
baz();
}
4 Cocoa模式
4.1 委托模式
委托对象不应该是strong,一个实现委托模式的类应该:
1. 实例变量命名为delegate 以显示这是个委托。
2. 因此,访存方法名就为delegate 和setDelegate。
3. delegate 变量不能设为strong, 应该设置为weak (最好不用assign)。
4.2 MVC模式
将模型与视图分离,将控制器从视图和模型中分离,回调APIs使用@protocol。
模型与视图分离: 不要对模型或数据源的表现形式做任何假设。保持数据与表现层的接口的抽象性。模型不对视图有任何了解(一个好的实践就是询问你自己是否能对数据有多个不同形式的表现方法)。
控制器从视图和模型中分离: 不要把“业务逻辑”放到视图相关的类;这会导致代码可复用性下降。让控制器的类承管代码,但不要对表现形式做太多假设。
用@protocol 定义回调APIs: 如果不是所有的方法都必须实现就使用@optional
5其它注意事项
- 头文件循环问题。模块组件的模块原则上只使用统一的头文件。
- warning 警告问题。解决原生代码的警告问题。
- 公共模块解耦问题。调计公用模块能够独立调用,相互不包含。
- 异常判断。
1 越界判断。objectAtIndex
2 nil 空值判断。函数参数为nil 时需要异常判断。 - 统一命名规范。同一模块前缀保持一致。
- 简称规定:
自选: HQ
直播: ZB
问答: WD - 结尾规定:
1 控制器: ViewController
2 视图:View
3 模型:Model
6上线注意事项 - 切换线上线下服务器地址。
2 切换H5服务器地址。
3 切换在线产品购买环境。
4 增加APP版本号。
5 检查在线更新。