最近重构项目组件,看到项目中存在一些命名和方法分块方面存在一些问题,结合平时经验和 Apple官方代码规范 在此整理出 iOS 工程规范。提出第一个版本,若是后期以为有不完善的地方,继续提出来不断完善,文档在此记录的目的就是为了你们的代码可读性较好,后来的人或者团队里面的其余人看到代码能够不会由于代码风格和可读性上面形成较大时间的开销。
软件的生命周期贯穿产品的开发,测试,生产,用户使用,版本升级和后期维护等过程,只有易读,易维护的软件代码才具备生命力。
- (void)getGooodsList { // ... } - (void)doHomework { if (self.hungry) { return; } if (self.thirsty) { return; } if (self.tired) { return; } papapa.then.over; }
//good if (condition1() && condition2() && condition3() && condition4()) { // Do something } //bad if (condition1() && condition2() && condition3() && condition4()) { // Do something }
return
来结束异常的状况。- (void)doHomework { if (self.hungry) { return; } if (self.thirsty) { return; } if (self.tired) { return; } papapa.then.over; }
// bad if (self.hungry) self.eat() // good if (self.hungry) { self.eat() }
switch (menuType) { case menuTypeLeft: { // ... break; } case menuTypeRight: { // ... break; } case menuTypeTop: { // ... break; } case menuTypeBottom: { // ... break; } }
每一个类型的命名以该类型结尾。html
ViewController
结尾。例子:ApplyRecordsViewControllerView
结尾。例子:分界线:boundaryViews
结尾。好比商品分类数据源。categoriesCell
结尾。好比 MyProfileCellDelegate
或者 Datasource
结尾。好比 XQScanViewDelegate有时候咱们须要为咱们建立的类设置一些注释。咱们能够在类的下面添加。git
枚举的命名和类的命名相近。github
typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) { UIControlContentVerticalAlignmentCenter = 0, UIControlContentVerticalAlignmentTop = 1, UIControlContentVerticalAlignmentBottom = 2, UIControlContentVerticalAlignmentFill = 3, };
_
链接。K
开头。后面遵循大写驼峰命名。「不带参数」#define HOME_PAGE_DID_SCROLL @"com.xq.home.page.tableview.did.scroll" #define KHomePageDidScroll @"com.xq.home.page.tableview.did.scroll"
书写规则,基本上就是 @property 以后空一格,括号,里面的 线程修饰词、内存修饰词、读写修饰词,空一格 类 对象名称
根据不一样的场景选择合适的修饰符。objective-c
@property (nonatomic, strong) UITableView *tableView; @property (nonatomic, assign, readonly) BOOL loading; @property (nonatomic, weak) id<#delegate#> delegate; @property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);
单例适合全局管理状态或者事件的场景。一旦建立,对象的指针保存在静态区,单例对象在堆内存中分配的内存空间只有程序销毁的时候才会释放。基于这种特色,那么咱们相似 UIApplication 对象,须要全局访问惟一一个对象的状况才适合单例,或者访问频次较高的状况。咱们的功能模块的生命周期确定小于 App 的生命周期,若是多个单例对象的话,势必 App 的开销会很大,糟糕的状况系统会杀死 App。若是以为非要用单例比较好,那么注意须要在合适的场合 tearDown 掉。shell
单例的使用场景归纳以下:缓存
+ (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //because has rewrited allocWithZone use NULL avoid endless loop lol. _sharedInstance = [[super allocWithZone:NULL] init]; }); return _sharedInstance; } + (id)allocWithZone:(struct _NSZone *)zone { return [TestNSObject sharedInstance]; } + (instancetype)alloc { return [TestNSObject sharedInstance]; } - (id)copy { return self; } - (id)mutableCopy { return self; } - (id)copyWithZone:(struct _NSZone *)zone { return self; }
推荐以 _
开头,写在 .m 文件中。例如 NSString * _somePrivateVariable安全
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath; - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (instancetype)init { self = [super init]; if (self) { <#statements#> } return self; } - (void)doHomework:(NSString *)name period:(NSInteger)second score:(NSInteger)score;
//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;
.m
文件中的私有方法须要在顶部进行声明文件基本上就是并发
//___FILEHEADER___ #import "___FILEBASENAME___.h" /*ViewController*/ /*View&&Util*/ /*model*/ /*NetWork InterFace*/ /*Vender*/ @interface ___FILEBASENAMEASIDENTIFIER___ () @end @implementation ___FILEBASENAMEASIDENTIFIER___ #pragma mark - life cycle - (void)viewWillAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidLoad { [super viewDidLoad]; self.title = <#value#>; } - (void)viewWillDisappear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidAppear:animated]; } #ifdef DEBUG - (void)dealloc { NSLog(@"%s",__func__); } #endif #pragma mark - public Method #pragma mark - private method #pragma mark - event response #pragma mark - UITableViewDelegate #pragma mark - UITableViewDataSource //...(多个代理方法依次往下写) #pragma mark - getters and setters @end
command+option+/
。三个快捷键解决。按需在旁边对方法进行说明解释、返回值、参数的说明和解释//
。采用 A.B.C 三位数字命名,好比:1.0.2,当有更新的状况下按照下面的依据app
版本号 | 右说明对齐标题 | 示例 |
---|---|---|
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 |
咱们知道了平时在使用 Xcode 开发的过程当中使用的系统提供的代码块所在的地址和新建控制器、模型、view等的文件模版的存放文件夹地址后,咱们就能够设想下咱们是否能够定制本身团队风格的控制器模版、是否能够打造和维护本身团队的高频使用的代码块?less
答案是能够的。
Xcode 代码块的存放地址:~/Library/Developer/Xcode/UserData/CodeSnippets
Xcode 文件模版的存放地址:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates/
@property (nonatomic, weak) id<<#delegate#>> delegate;
,你输入 Property_block 就会出来 @property (nonatomic, copy) <#returnType#> (^<#Block#>)(<#parType#>);
咱们能够将属性、控制器生命周期方法、单例构造一个对象的方法、代理方法、block、GCD、UITableView 懒加载、UITableViewCell 注册、UITableView 代理方法的实现、UICollectionVIew 懒加载、UICollectionVIewCell 注册、UICollectionView 的代理方法实现等等组织为 codesnippets
封装好 codesnippets 以后团队除了你编写这个项目的人如何使用?如何知道是否有这个代码块?
方案:先在团队内召开代码规范会议,你们都统一知道这个事情在。以后你们共同维护 codesnippets。用法见下
属性:经过 Property_类型 开头,回车键自动补全。好比 Strong 类型,编写代码经过 Property_Strong 回车键自动补全成以下格式
@property (nonatomic, strong) <#Class#> *<#object#>;
方法:以 Method_关键词 回车键确认,自动补全。好比 Method_UIScrollViewDelegate 回车键自动补全成 以下格式
#pragma mark - UIScrollViewDelegate - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
}
各类常见的 Mark:以 **Mark_关键词** 回车确认,自动补全。好比 Method_MethodsGroup 回车键自动补全成 以下格式
#pragma mark - life cycle
#pragma mark - public Method
#pragma mark - private method
#pragma mark - event response
#pragma mark - UITableViewDelegate
#pragma mark - UITableViewDataSource
#pragma mark - getters and setters
- 封装好 codesnippets 以后团队内如何统一?想到一个方案,能够将团队内的 codesnippets 共享到 git,团队内的其余成员再从云端拉取同步。这样的话团队内的每一个成员均可以使用最新的 codesnippets 来编码。 编写 shell 脚本。几个关键步骤: 1. 给系统文件夹受权 2. 在脚本所在文件夹新建存放代码块的文件夹 3. 将系统文件夹下面的代码块复制到步骤2建立的文件夹下面 4. 将当前的全部文件提交到 Git 仓库 ## 文件模版的改造 咱们观察系统文件模版的特色,和在 Xcode 新建文件模版对应。  因此咱们新建 Custom 文件夹,将系统 Source 文件夹下面的 Cocoa Touch Class.xctemplate 复制到 Custom 文件夹下。重命名为咱们须要的名字,我这里以“Power”为例  进入 PowerViewController.xctemplate/PowerViewControllerObjective-C 修改 `___FILEBASENAME___.h` 和 `___FILEBASENAME___.m` 文件内容  在替换 .h 文件内容的时候后面改成 UIViewController,否则其余开发者新建文件模版的时候出现的不是 UIViewController 而是咱们的 PowerViewController  修改 TemplateInfo.plist  思考: - 如何使用 商量好一个标识(“Power”)。好比我新建了单例、控制器、Model、UIView、UITableViewCell、UICollectionViewCell6个模版,都觉得 Power 开头。  - 如何共享 以 shell 脚本为工具。使用脚本将 git 云端的代码模版同步到本地 Xcode 文件夹对应的位置就可使用了。关键步骤: 1. git clone 代码到脚本所在文件夹 2. 进入存放 codesnippets 的文件夹将内容复制到系统存放 codesnippets 的地方 3. 进入存放 file template 的文件夹将内容复制到系统存放 file template 的地方 ## 内容及其如何使用 1. Property 属性。敲 **Property_** 自动联想,光标移动选中后敲回车自动补全 2. Mark 标识。 敲 **Mark_** 自动联想,会展现各类经常使用的 Mark,光标移动选中后敲回车自动补全 3. Method 方法。敲 **Method_** 自动联想,会展现各类经常使用的 Method,光标移动选中后敲回车自动补全 4. GCD。敲 **GCD_** 自动联想,会展现各类经常使用的 GCD,光标移动选中后敲回车自动补全 5. 经常使用 UI 控件的懒加载。敲 **_init** 自动联想,展现经常使用的 UI 控件的懒加载,光标移动选中后敲回车自动补全 6. Delegate。敲 **Delegate_** 自动联想,会展现各类经常使用的 Delegate,光标移动选中后敲回车自动补全 7. Notification。敲 **NSNotification_** 自动联想,会展现各类经常使用的 NSNotification 的代码块,好比发送通知、添加观察者、移除观察者、观察者方法的实现等等,光标移动选中后敲回车自动补全 8. Protocol。敲 **Protocol_** 自动联想,会展现各类经常使用的 Protocol 的代码块,光标移动选中后敲回车自动补全 9. 内存修饰代码块 10. 工程经常使用 TODO、FIXME、Mark。敲 **Mark_** 自动联想,会展现各类经常使用的 Mark 的代码块,光标移动选中后敲回车自动补全 11. 内存修饰代码块。敲 **Memory_** 自动联想,会展现各类经常使用的内存修饰的代码块,光标移动选中后敲回车自动补全 12. 一些经常使用的代码块。敲 **Thread_** 等自动联想,选中后敲回车自动补全。 ## 使用
chmod +x ./syncSnippets.sh // 为脚本设置可执行权限
chmod +x ./uploadMySnippets.sh // 为脚本设置可执行权限
./syncSnippets.sh // 同步git云端代码块和文件模版到本地
./uploadMySnippets.sh //将本地的代码块和文件模版同步到云端
## PS **不断完善中。你们有好用或者不错的代码块或者文件模版但愿参与到这个项目中来,为咱们开发效率的提高添砖加瓦、贡献力量** 目前新建了大概58个代码段和6个类文件模版(UIViewController控制器带有方法组、模型、线程安全的单例模版、带有布局方法的UIView模版、UITableViewCell、UICollectionViewCell模版) shell 脚本基本有每一个函数和关键步骤的代码注释,想学习 shell 的人能够看看代码。[代码传送门](https://github.com/FantasticLBP/codesnippets)