iOS开发规范
编写目的
年底工作汇报的时候有同事提出开发规范的问题,抽空就整理了一下iOS开发的代码规范。
制定开发规范,可以在团队内部形成统一的开发习惯,减少协作的理解成本。
此开发规范主要制定了代码格式、注释习惯、命名规则方面的规范:
编程规约
一、命名规范
统一要求
含义清楚,尽量做到不需要注释也能了解其作用,若做不到,就加注释。
使用全称,不适用缩写
类的命名
大驼峰式命名:每个单词的首字母都采用大写字母
例子:RSHomeController
后缀要求
ViewController: 使用Controller做后缀
例子: RSHomeController
View: 使用View做后缀
例子: JLBAlertView
UITableCell:使用Cell做后缀
例子: OrderListTitleCell
Protocol: 使用Delegate或者DataSource作为后缀
例子: UITableViewDelegate
UI控件依次类推
私有变量
小驼峰式命名:第一个单词以小写字母开始,后面的单词的首字母全部大写。
例子:firstName、lastName
以下划线 _ 开头,第一个单词首字母小写
例子:NSString * _myPrivateVariable
私有变量放在 .m 文件中声明
property变量
小驼峰式命名:
例子:
/**注释*/
@property (nonatomic, copy) NSString *userName;
注:禁止使用synthesize关键词
宏命名
全部大写,单词间用 下划线_ 分隔。[不带参数]
例子: #define THIS_IS_AN_MACRO @"THIS_IS_AN_MACRO"
以字母 k 开头,后面遵循大驼峰命名。[不带参数]
例子:#define kScreenHeight ([UIScreen mainScreen].bounds.size.height)
小驼峰命名。[带参数]
例子:#define rgbColor(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
Delegate命名
- 类的实例必须为回调方法的参数之一, 如:
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
- 回调方法的参数只有类自己的情况,方法名要符合实际含义, 如:
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
- 以类的名字开头(回调方法存在两个以上参数的情况)以表明此方法是属于哪个类的, 如:
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- 使用did和will通知Delegate已经发生的变化或将要发生的变化, 如:
-(NSIndexPath*)tableView:(UITableView*)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath;
-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath;
二、私有方法及变量声明
声明位置
- 在.m文件中最上方,定义空的category进行声明
@interface OrderListTitleFrame ()
// 属性
@property (nonatomic, strong) UIBarButtonItem *backBtn;
// 私有方法
- (CGFloat)cellHeight;
@end
@implementation OrderListTitleFrame
// 私有方法的实现
- (CGFloat)cellHeight
{
//some code
}
@end
点语法
应该始终使用 点语法 来访问或者修改属性,访问其他实例时首选括号。
例如:
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
条件判断
条件判断主体部分应该始终使用大括号括住来防止出错,即使它可以不用大括号(例如它只需要一行)。这些错误包括添加第二行(代码)并希望它是 if 语句的一部分时。还有另外一种更危险的,当 if 语句里面的一行被注释掉,下一行就会在不经意间成为了这个 if 语句的一部分。此外,这种风格也更符合所有其他的条件判断,因此也更容易检查。
推荐:
if (!error) {
return success;
}
反对:
if (!error)
return success;
或者:
if (!error) return success;
变量
变量名应该尽可能命名为描述性的。除了 for() 循环外,其他情况都应该避免使用单字母的变量名。*号表示指针属于变量,例如:NSString text 不要写成 NSString text 或者 NSString * text,常量除外。
尽量定义属性来代替直接使用实例变量。除了初始化方法init, initWithCoder:等,dealloc方法和自定义的setters和 getters内部,应避免直接访问实例变量。
推荐:
@interface NYTSection: NSObject
@property (nonatomic) NSString *headline;
@end
反对:
@interface NYTSection : NSObject {
NSString *headline;
}
init 和 dealloc
dealloc方法应该放在实现文件的最上面,并且刚好在 @synthesize和@dynamic语句的后面。在任何类中,init都应该直接放在dealloc方法的下面。
- (instancetype)init {
self = [super init]; // 或者调用指定的初始化方法
if (self) {
// Custom initialization
}
return self;
}
CGRect 函数
All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.
简单翻译一下。所有功能描述在这个参考CGRect中隐式数据结构作为输入规范那些矩形之前计算结果。由于这个原因,您的应用程序应该避免直接阅读和写作在CGRect中存储的数据的数据结构。相反,使用这里描述的函数来操纵矩形和检索他们的特征。
大概就是当访问一个 CGRect 的 x, y, width, height 时,应该使用 CGGeometry 函数代替直接访问结构体成员
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
常量
常量首选内联字符串字面量或数字,因为常量可以轻易重用并且可以快速改变而不需要查找和替换。常量应该声明为 static 常量而不是 #define ,除非非常明确地要当做宏来使用。
推荐:
static NSString * const NYTAboutViewControllerCompanyName = @"The New York Times Company";
static const CGFloat NYTImageThumbnailHeight = 50.0;
反对:
#define CompanyName @"The New York Times Company"
#define thumbnailHeight 2
Bool
因为 nil 解析为 NO,所以没有必要在条件中与它进行比较。永远不要直接和 YES 进行比较,因为 YES 被定义为 1,而 BOOL 可以多达 8 位。
这使得整个文件有更多的一致性和更大的视觉清晰度。
推荐:
if (!someObject) {
}
反对:
if (someObject == nil) {
}
三、注释规范
最好的代码是不需要注释的,尽量通过合理的命名、良好的代码把含义表达清楚,在必要的地方添加注释,注释需要与代码同步更新,如果做不到命名尽量的见名知意的话,就可以适当的添加一些注释或者mark
属性注释
/**学生*/
@property (nonatomic, strong) Student *student;
方法声明注释:
/**
订单列表页接口
@param psize [可选]: 每页条数
@param page [可选]: 页数
@param control 当前类
@param success 成功回调
@param failure 失败回调
*/
+ (void)getOrderListDataWithPsize:(NSInteger)psize
page:(NSInteger)page
control:(NSObject *)control
success:(void (^)(NSArray *dataArray))success
failure:(void (^)(NSError *error))failure;
导入
如果有一个以上的 import 语句,就对这些语句进行分组。每个分组的注释是可选的。
// Frameworks
@import QuartzCore;
// Models
#import "NYTUser.h"
// Views
#import "NYTButton.h"
#import "NYTUserView.h"
四、代码格式
代码统一,可以让代码更加易读,降低后续维护成本。
* 位置
例子: NSString *userName;
方法的声明和定义
在 - 、+ 和 返回值 之间留一个空格,方法名和第一个参数之间不留空格
- (id)initWithNibName:(NSString *)nibNameOrNilbundle:(NSBundle *)nibBundleOrNil
{
// some code
}