1. 工程文件结构
所有的文件应放在工程中的项目目录下。
项目文件和物理文件需保持一致。
Xcode 创建的任何组 (group) 都必须在文件系统中有映射。
项目文件不仅可以按照业务类型分组,也可以根据功能分组。
2. 代码格式规范
2.1 代码注释格式
文件注释:采用 Xcode 自动生成的注释格式。
//
// AppDelegate.h
// 项目名称
//
// Created by 开发者姓名 on 2018/6/8.
// Copyright © 2018 年 公司名称. All rights reserved.
//
import 注释:如果有一个以上的 import 语句,对这些语句进行分组,每个分组的注释是可选的。
// Framework
#import <UIKit/UIKit.h>
// Model
#import “WTUser.h”
// View
#import “WTView.h”
方法注释:Xcode8 之后快捷键自动生成(option + command + /)。
/**
<#Description#>
@param application <#application description#>
@param launchOptions <#launchOptions description#>
@return <#return value description#>
*/
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
代码块注释:单行的用“// + 空格”开头,多行用“/ /”。
2.2 代码结构与排版
声明文件:方法顺序和实现文件的顺序保持一致,根据需要用”#pragma mark -“将方法分组。
实现文件:必须用”#pragma mark -“将方法分组。分组前后优先级:Lifecycle 方法 > Public 方法 > UI 方法 > Data 方法 > Event 方法 > Private 方法(逻辑处理等) > Delegate 方法 > 部分 Override 方法 > Setter 方法 > Getter 方法。
#pragma mark – Lifecycle
– (instancetype)init {}
– (void)viewDidLoad {}
– (void)viewWillAppear:(BOOL)animated {}
– (void)viewDidAppear:(BOOL)animated {}
– (void)viewWillDisappear:(BOOL)animated {}
– (void)viewDidDisappear:(BOOL)animated {}
– (void)didReceiveMemoryWarning {}
– (void)dealloc {}
#pragma mark – Public
– (void)refreshData {}
#pragma mark – UI
– (void)initSubViews {}
#pragma mark – Data
– (void)initData {}
– (void)constructData {}
#pragma mark – Event
– (void)clickButton:(UIButton *)button {}
#pragma mark – Private
– (CGFloat)calculateHeight {}
#pragma mark – UIScrollViewDelegate
– (void)scrollViewDidScroll:(UIScrollView *)scrollView {}
#pragma mark – Override
– (BOOL)needNavigationBar {}
#pragma mark – Setter
– (void)setWindow:(UIWindow *)window {}
#pragma mark – Getter
– (UIWindow *)window {}
变量:优先使用属性声明而非变量声明,注意属性修饰符、变量类型、变量之间的间隔。
@property (strong, nonatomic) UIWindow *window;
点语法:应始终使用点语法来访问和修改属性。
间距要求如下:
一个缩进使用四个空格。
在”-“或者”+“号之后应该有一个空格,方法的大括号和其它大括号始终和声明在同一行开始,在新的一行结束,另外方法之间应该空一行。
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (door.isClosed) {
// Do something
} else {
// Do something
}
return YES;
}
长度要求如下:
每行代码的长度不应该超过 100 个字符。
单个函数或方法的实现代码控制在 50 行以内。
单个文件里的代码行数控制在 500~600 行之内。
3. 代码命名规范
3.1 代码命名基础
最好是既清晰又简短,但不要为简短丧失清晰性,并使用驼峰命名法。
名称通常不缩写,即使名称很长也要拼写完全(禁止拼音),然而可使用少数非常常见的缩写,部分举例如下:
常用缩写词
含义
常用缩写词
含义
app
application
max
maximum
alt
alternate
min
minimum
calc
calculate
msg
message
alloc
allocte
rect
rectangle
dealloc
deallocte
msg
message
init
initialize
temp
temporary
int
integer
func
function
由于 Cocoa(Objective-C)没有 C ++ 一样的命名空间机制,需添加前缀(公司名首字母)防止命名冲突,前缀使用 2 个字符(以下统称项目前缀)。
常见的单词略写:ASCII,PDF,HTTP,XML,URL,JPG,GIF,PNG,RGB 等
3.2 类和协议命名
类名应明确该类的功能,并且要有项目前缀防止命名冲突。
协议组合一组方法作为一个类的部分接口使用,用类名作为协议名,例如:NSObject。
协议仅仅组合一组方法而不关联具体类,这种协议的命名应采用动名词形式(ing)。
委托形式的协议命名为类名加上 Delegate,例如:UIScrollViewDelegate。
3.3 变量和属性命名
变量名应前置下划线“_”, 属性名没有下划线。
属性本质上是存取方法 setter/getter, 可进行重写(注意内存管理)。
@property (strong, nonatomic) UIWindow *window;
– (void)setWindow:(UIWindow *)window;
– (UIWindow *)window;
可以适当的对 setter/getter 进行别名设置。
@property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteractionEnabled;
3.4 方法和函数命名
方法名和函数名一般不需要前缀,但函数(C 语言形式)作为全局作用域的时候最好加上项目前缀。
表示行为的方法名称以动词开头,但不要使用 do/does 等无实际意义的助动词。
参数前面的单词要能够描述该参数,并且参数名最好能用描述该参数的单词命名。
– (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
方法中多个参数可以使用适当的介词进行连接。
// 后续多个参数使用 with
– (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
// 添加适当介词能够使方法的含义更明确
– (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;
// 第一个参数用了 with,后面的参数不使用 with
– (instancetype)initWithImage:(nullable UIImage *)image highlightedImage:(nullable UIImage *)highlightedImage;
只有在方法返回多个值的时候使用 get 单词进行明确。
– (void)getLineDash:(nullable CGFloat *)pattern count:(nullable NSInteger *)count phase:(nullable CGFloat *)phase;
方法返回某个对象实例。
// 类方法创建对象
+ (instancetype)buttonWithType:(UIButtonType)buttonType;
// 单例命名
+ (UIApplication *)sharedApplication;
委托或代理方法命名第一个参数最好能相关某个对象。
– (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
私有方法不要以下划线“_“开头,因为系统私有方法保留此方式。
自定义方法和系统方法重名,建议在方法开头加前缀”xx_methodName“。
3.5 常量和宏的命名
const 常量外部声明:在 Objective- C 文件中优先采用 FOUNDATION_EXTERN 和 UIKIT_EXTERN,而非 C 语言中的 extern。
const 常量采用驼峰命名原则。
const 常量根据作用域适当加上前缀(含项目前缀):可供外部使用需加上相应的类名或者模块前缀,仅文件内部使用需要加上小写字母“k”.
宏定义每个字母采用大写,单词之间用下划线“_”间隔。
宏定义也可根据作用范围加上适当前缀,避免命名冲突。
3.6 枚举的命名
使用枚举来定义一组相关的整数常量,增强代码的可读性。
枚举可根据作用域添加前缀(含项目前缀),格式:[相关类名或功能模块名] + [描述] + [状态]。
建议优先采用 Objective- C 的声明 NS_ENUM 和 NS_OPTIONS,少采用 C 语言形式的 enum 等枚举声明.
枚举定义时需指定 None 状态,并且其 rawValue 一般为起始值 0。
// NS_ENUM
typedef NS_ENUM(NSInteger, UIStatusBarAnimation) {
UIStatusBarAnimationNone = 0,
UIStatusBarAnimationFade = 1,
UIStatusBarAnimationSlide = 2,
}
typedef NS_OPTIONS(NSUInteger, UIRemoteNotificationType) {
UIRemoteNotificationTypeNone = 0,
UIRemoteNotificationTypeBadge = 1 << 0,
UIRemoteNotificationTypeSound = 1 << 1,
UIRemoteNotificationTypeAlert = 1 << 2,
UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3,
}
3.7 通知命名
外部声明:在 Objective- C 文件中优先采用 FOUNDATION_EXTERN 和 UIKIT_EXTERN,而非 C 语言中的 extern。
通知的命名一般都是跨文件使用的,需添加项目前缀。
// [相关联类名或者功能模块名] + [will/Did](可选)+ [描述] + Notification
UIApplicationDidEnterBackgroundNotification
UIApplicationWillEnterForegroundNotification
3.8 类型别名命名
根据作用域添加前缀(含项目前缀),格式:[类名或功能模块名] + [描述]。
4. 文件资源命名规范
资源文件命名也需加上项目前缀。
资源文件名全小写,单词之间用下划线“_”间隔。
资源文件命名格式:[项目前缀] + [业务] + [文件名]
图片文件命名格式:[项目前缀] + [业务] + [类型] + [状态]。
// 常见类型:logol,icon,img
// 常见状态:normal,selected,highlight
UIImage *image = [UIImage imageNamed:@”wt_setting_icon_normal”];
5. 代码警告处理
注意警告问题的隐蔽性,因此最好修复警告。
警告类型的查看步骤:选中警告 -> 右键 Reveal in Log(不编译 Reveal in Log 是灰色的,因此先编译)-> 查看方括号的内容
如果需要忽略警告,建议优先代码 push 或者 pop 处理。
#pragma clang diagnostic push
#pragma clang diagnostic ignored “-Warc-retain-cycles”
// 造成警告的代码
#pragma clang diagnostic pop
如果警告数量过大,检查警告类型以及必要性,可 xcode 配置忽略此类型警告。步骤:选中工程 -> TARGETS -> Build Settings -> Other Warning Flags。
忽略单个和全局配置稍有差别,如下举例:
push/pop Other Warning Flags
-Wformat —-> -Wno-format
-Wunused-variable —-> -Wno-unused-variable
-Wundeclared-selector —-> -Wno-undeclared-selector
-Wint-conversion —-> -Wno-int-conversion
也可以在 pch 等大范围作用域的头文件中添加代码来忽略后续警告:#pragma clang diagnostic ignored“警告名称”。
6. 外部库文件引入
库文件引入最好把警告处理掉。
库文件引入优先采用 CocoaPods 引入,并且指定版本号。
源文件方式需引入文件到工程目录下。
源文件方式需注意有无版本说明信息(可能在 README 文件中,也可能在某个.h 头文件中,又或者有 Version 文件)没有时需在库文件目录下新增版本说明文件,
7. 代码版本管理
版本管理工具:svn 或 git。
svn 文件管理配置: 目录~/.subversion 打开 config 文件配置 global-ignore。
git 文件管理配置:.gitignore 文件记录了被 git 忽略的文件,作用于本仓库,常见语法如下:
井号(#)用来添加注释用的,比如 “# 注释 ”。
build/ : 星号()是通配符,build/* 则是要说明要忽略 build 文件夹下的所有内容。
*.pbxuser : 表示要忽略后缀名为.pbxuser 的文件。
!default.pbxuser : 感叹号(!)是取反的意思,*.pbxuser 表示忽略所有后缀名为.pbxuser 的文件,如果加上!default.pbxuser 则表示,除了 default.pbxuse 忽略其它后缀名为 pbxuse 的文件。
提交信息规范:
BUG 类型为“Fix + [BUG 编号] + [BUG 描述]”。
任务类型为“Done + [任务编号] + [任务描述]”。
任务中间态为“Doing + [任务编号] + [任务描述]”。
引入类库为“import + [类库名]”。
8. 构建和分发
手动构建:Xcode 界面化构建注、xcodebuild 终端命令构建。
自动化构建:Jenkins+Fastlane、xcodebuild 脚本执行。
内测分发渠道:fir.im、蒲公英等。
线上分发渠道:AppStore。