移动端iOS开发规范文档
序言
- 根据网上的一些OC编码规范整理归纳而成,为了利于项目维护以及规范开发,促进成员之间
Code Review
的效率
函数的书写
- 方法长度建议不超过80行,如果方法太长可以考虑抽取其中一部分
- 方法(-、+)和返回值前面的左括号间隔一个空格,方法参数直接间隔一个空格。每个方法结束后需间隔一行来书写新方法
- (void)applicationDidEnterBackground:(UIApplication *)application
- (void)applicationWillResignActive:(UIApplication *)application
- 如果一个函数有特别多的参数或者名称特别长,将其按照:来对齐分行显示
-(id)initWithModel:(IPCModle)model
ConnectType:(IPCConnectType)connectType
Resolution:(IPCResolution)resolution
AuthName:(NSString *)authName
Password:(NSString *)password
MAC:(NSString *)mac
AzIp:(NSString *)az_ip
AzDns:(NSString *)az_dns
Token:(NSString *)token
Email:(NSString *)email
Delegate:(id<IPCConnectHandlerDelegate>)delegate;
函数的调用
函数调用的格式和书写的差不多,可以按照函数的长短选择写在一行或者分成多行
//写在一行
[myObject doFooWith:arg1 name:arg2 error:arg3];
//分行写,按照 : 对齐
[myObject doFooWith:arg1
name:arg2
error:arg3];
//第一段名称过短的话后续可以进行缩进
[myObj short:arg1
longKeyword:arg2
evenLongerKeyword:arg3
error:arg4];
闭包
-
block
的右括号"}"应该和调用block
那行代码的第一个非空字符对齐 -
block
内的代码采用一个tab
(四个空格的距离)的缩进 - 如果
block
过于庞大,应该单独声明一个变量来使用
//分行书写的block,内部使用一个tab的缩进
[operation setCompletionBlock:^{
[self.delegate newDataAvailable];
}];
//使用C语言API调用的block遵循同样的书写规则
dispatch_async(_fileIOQueue, ^{
NSString* path = [self sessionFilePath];
if (path) {
// ...
}
});
//庞大的block应该单独定义成变量使用
void (^largeBlock)(void) = ^{
// ...
};
[_operationQueue addOperationWithBlock:largeBlock];
//在一个调用中使用多个block,通过进行一个tab缩进
[myObject doSomethingWith:arg1
firstBlock:^(Foo *a) {
// ...
}
secondBlock:^(Bar *b) {
// ...
}
];
命名规范
项目命名
·项目名都遵循大驼峰命名。例如:AoRiseProject
Bundle Identifier 命名
·Bundle Identifier
:采用反域名命名规范,全部采用小写字母,以域名后缀+公司顶级域名+应用名形式命名,例如:com.rogrand.dianbangbang
类名
类的命名都遵循大驼峰命名。一般是:前缀 + 功能 + 类型
。例如:CPX + Login + ViewController
,在实际开发中,一般都会给工程中所有的类加上属于本工程的前缀。
常用控件类命名类型对照表(下表中前缀为:CPX
,如果用到下表中没有列举出来,请去掉UI首字母,遵循实际规则即可。)
控件名 | 类型 | 示例 |
---|---|---|
UIViewController | ViewController | CPXBaseViewController |
UView | View | CPXBaseView |
UITableView | TableView | CPXOrderTableView |
UITableViewCell | Cell | CPXOrderListCell |
UIButton | Button | CPXSuccessButton |
UILabel | Label | CPXSuccessLabel |
UIImageView | ImgView | CPXGoodsImgView |
UITextField | TextField | CPXNameTextField |
UITextView | TextView | CPXSuggestTextView |
常量
·宏:小写k+大驼峰 即为:#define kUserAgeKey @“ageKey”
·全局常量:工程前+缀全大写,下划线隔开 即为:extern const NSString MW_USER_AGE_KEY
清晰
- 命名应该尽可能的清晰和简洁,但在Objective-C中,清晰比简洁更重要
//清晰
insertObject:atIndex:
//不清晰,insert的对象类型和at的位置属性没有说明
insert:at:
- 不要使用单词的简写,拼写出完整的单词
//清晰
destinationSelection:setBackgroundColor:
//不清晰,不要使用简写
destSel:setBkgdColor:
- 命名方法或者函数时要避免歧义
//有歧义,是返回sendPort还是send一个Port?
sendPort
//有歧义,是返回一个名字属性的值还是display一个name的动作?
displayName
命名统一使用驼峰命名法;只采纳有广为人知含义的缩写,比如
info
、msg
、UI
、HTTP
这类。自造的缩写不被认可。总体的命名原则是清晰和一致,避免歧义。类名需要结合项目名称来命名,确保整个项目中的自定义类的名称开头是统一的,同样要确保类名需要大写字母开头。
类名命名需结合功能或者模块,并且尾部要带上该类的类型,比如
UIViewController的子类命名为JasonIndexViewController。
UIViewController 后缀添加“Controller”
UIView 后缀添加“View”
UIButton 后缀添加“Button"或者"Btn"
UILabel 后缀添加“Label"
一致性
- 整个工程的命名风格要保持一致性,最好和苹果SDK的代码保持统一。不同类中完成相似功能的方法应该叫一样的名字,比如我们总是用
count
来返回集合的个数,不能在A
类中使用count
而在B
类中使用getNumber
。
命名方法
- OC的命名方法通常比较长,是为了让程序有更好的可读性,目的是为了可以当成一个句子的形式朗读出来,达到见名知意的效果
- 方法一般以小写字母打头,每一个后续的单词首字母大写,方法名中不应该有标点符号(包括下划线),有两个例外:
- 可以用一些通用的大写字母缩写打头方法,比如
PDF
,TIFF
等。 - 可以用带下划线的前缀来命名私有方法或者类别中的方法。
- 可以用一些通用的大写字母缩写打头方法,比如
如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用do
,does
这种多余的关键字,动词本身的暗示就足够了:
//动词打头的方法表示让对象执行一个动作
- (void)invokeWithTarget:(id)target;
- (void)selectTabViewItem:(NSTabViewItem *)tabViewItem;
如果方法是为了获取对象的一个属性值,直接用属性名称来命名这个方法,注意不要添加get
或者其他的动词前缀:
//正确,使用属性名来命名方法
- (NSSize)cellSize;
//错误,添加了多余的动词前缀
- (NSSize)calcCellSize;
- (NSSize)getCellSize;
对于有多个参数的方法,务必在每一个参数前都添加关键词,关键词应当清晰说明参数的作用:
//正确,保证每个参数都有关键词修饰
- (void)cycleScrollView:(SDCycleScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index
//错误,遗漏关键词
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
//正确
- (id)viewWithTag:(NSInteger)Tag;
//错误,关键词的作用不清晰
- (id)taggedView:(int)Tag;
不要用and
来连接两个参数,通常and
用来表示方法执行了两个相对独立的操作(从设计上来说,这时候应该拆分成两个独立的方法):
//错误,不要使用and来连接参数
- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;
//正确,使用and来表示两个相对独立的操作
- (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;
命名通知
通知常用于在模块间传递消息,所以通知要尽可能地表示出发生的事件,通知的命名方式是:
code[触发通知的类名] + [ Did | Will ] + [动作] + Notification
举个栗子
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
注释
文件注释
- 举个栗子
/*******************************************************************************
Copyright (C), 2011-2013, Andrew Min Chang
File name: AMCCommonLib.h
Author: Andrew Chang (Zhang Min)
E-mail: [email protected]
Description:
This file provide some covenient tool in calling library tools. One can easily include
library headers he wants by declaring the corresponding macros.
I hope this file is not only a header, but also a useful Linux library note.
History:
2012-??-??: On about come date around middle of Year 2012, file created as "commonLib.h"
2012-10-10: Change file name as "AMCCommonLib.h"
2012-12-04: Add UDP support in AMC socket library
2013-01-07: Add basic data type such as "sint8_t"
2013-01-18: Add CFG_LIB_STR_NUM.
2013-01-22: Add CFG_LIB_TIMER.
2013-01-22: Remove CFG_LIB_DATA_TYPE because there is already AMCDataTypes.h
Copyright information:
This file was intended to be under GPL protocol. However, I may use this library
in my work as I am an employee. And my company may require me to keep it secret.
Therefore, this file is neither open source nor under GPL control.
********************************************************************************/
/*************************************************************
* Copyright (c) xxx科技有限公司
* All rights reserved.
*
* 文件名称: xxx
* 文件标识: xxx
* 摘要说明: xxx
*
* 当前版本: 1.0.0
* 作 者: CPX
* 更新日期:
* 整理修改:
*
***************************************************************/
文件注释的格式通常不作要求,能清晰易读就可以了,但在整个工程中风格要统一。
代码注释
- 方法、函数、类、协议、类别的定义都需要注释,推荐采用Apple的标准注释风格,好处是可以在引用的地方
alt+command+/
点击自动弹出注释,非常方便
/**
* Get the COPY of cloud device with a given mac address.
*
* @param macAddress Mac address of the device.
*
* @return Instance of IPCCloudDevice.
*/
-(IPCCloudDevice *)getCloudDeviceWithMac:(NSString *)macAddress;
- 协议、委托的注释要明确说明其被触发的条件
// Individual rows can opt out of having the -editing property set for them. If not implemented, all rows are assumed to be editable.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
UI布局规范
·建议项目统一使用Masonry
和xib
结合的方式布局。不允许出现直接设置frame
的情况。如果是纯代码的项目,不允许出现xib和拉约束的情况。不允许
纯storyboard
开发。
· 提取方法,去除重复代码。对于必要的工具类抽取也很重要,这在以后的项目中是可以重用的。
· 尽可能的使用局部变量
· 尽量减少对变量的重复计算
· 尽量在合适的场合使用单例。使用单例可以减轻加载的负担,缩短加载的时间,提高加载效率。注意:并不是所有的地方都适用于单例
编码规范
- 使用
#pragma mark
来分类方法,参考以下结构,通常将不常用的函数方法写在底部,这里强制要求懒加载必须写在底部
#pragma mark – Life Cycle
#pragma mark - Events
#pragma mark – Private Methods
#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate
#pragma mark - Custom Delegates
#pragma mark – Getters and Setters
- 枚举的定义参考系统定义枚举方式
typedef NS_ENUM(NSUInteger, UISearchBarStyle) {
UISearchBarStyleDefault, // currently UISearchBarStyleProminent
UISearchBarStyleProminent, // used my Mail, Messages and Contacts
UISearchBarStyleMinimal // used by Calendar, Notes and Music
}
-
if
和case
语句,不论if
或者else
下有一个还是多个语句,都必须带上大括号。同样case
语句也是如此。
//正确
if (!error) {
return success;
}
//错误
if (!error)
return success;
或
if (!error) return success;
- 布尔值推荐写法
if (someObject) {
//...
}
if (![anotherObject boolValue]) {
//...
}
- 当需要提高代码的清晰性和简洁性时,三元操作符才会使用。
//推荐写法
NSInteger value = 5;
result = (value != 0) ? x : y;
BOOL isHorizontal = YES;
result = isHorizontal ? x : y;
//不推荐写法
result = a > b ? x = c > d ? c : d : y;
-
CGRect
函数
//推荐写法
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
//不推荐的写法
CGRect frame = self.view.frame;
CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;
- 当使用条件语句编码时,不要嵌套
if
语句,多个返回语句也是OK
//推荐写法
- (void)someMethod {
if (![someOther boolValue]) {
return;
}
//Do something important
}
//不推荐写法
- (void)someMethod {
if ([someOther boolValue]) {
//Do something important
}
}
- 单例模式
//单例对象应该使用线程安全模式来创建共享实例
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
资源文件规范
· 全部小写,采用下划线命名法,加前缀区分。所有的资源文件都需要加上工程前缀(小写形式)。
· 命名模式:可加后缀_small
表示小图,_big
表示大图,逻辑名称可由多个单词加下划线组成,采用以下规则:
用途_模块名_逻辑名称
用途_模块名_颜色
用途_逻辑名称
用途_颜色
说明 | 前缀(工程前缀示例MW) | 示例 |
---|---|---|
按钮相关 | mw_btn_ | mw_btn_home_normal、mw_btn_red,mw_btn_red_big |
背景相关 | mw_bg_ | mw_bg_home_header、mw_bg_main |
图标相关 | mw_icon_ | mw_icon_home_location、mw_icon_input |
分割线相关 | mw_div_ | mw_div_home_location、mw_div_input |
默认相关 | mw_def_ | mw_def_home_location、mw_def_input |
版本规范
· 采用A.B.C
三位数字命名,比如:1.0.2
,当有版本更新的时候,依据下面的情况来确定版本号规范。
版本号 | 说明 | 示例 |
---|---|---|
A.b.c | 属于重大更新内容 | 1.0.0 -> 2.0.0 |
a.B.c | 属于小部分更新内容 | 1.0.2 -> 1.2.2 |
a.b.C | 属于补丁更新内容 | 1.0.2 -> 1.0.4 |
其他规范
· 检测内存泄漏。可使用Instruments加上其他第三方工具辅助分析内存。