本文共 10713 字,大约阅读时间需要 35 分钟。
最近重构项目组件,看到项目中存在一些命名和方法分块方面存在一些问题,结合平时经验和 Apple官方代码规范 在此整理出 iOS 工程规范。提出第一个版本,如果后期觉得有不完善的地方,继续提出来不断完善,文档在此记录的目的就是为了大家的代码可读性较好,后来的人或者团队里面的其他人看到代码可以不会因为代码风格和可读性上面造成较大时间的开销。
软件的生命周期贯穿产品的开发,测试,生产,用户使用,版本升级和后期维护等过程,只有易读,易维护的软件代码才具有生命力。
- (void)getGooodsList{ // ...}- (void)doHomework{ if (self.hungry) { return; } if (self.thirsty) { return; } if (self.tired) { return; } papapa.then.over;}
//goodif (condition1() && condition2() && condition3() && condition4()) { // Do something}//badif (condition1() && condition2() && condition3() && condition4()) { // Do something }
return
来结束异常的情况。- (void)doHomework{ if (self.hungry) { return; } if (self.thirsty) { return; } if (self.tired) { return; } papapa.then.over;}
// badif (self.hungry) self.eat() // goodif (self.hungry) { self.eat()}
switch (menuType) { case menuTypeLeft: { // ... break; } case menuTypeRight: { // ... break; } case menuTypeTop: { // ... break; } case menuTypeBottom: { // ... break; }}
ViewController
结尾。例子:ApplyRecordsViewControllerView
结尾。例子:分界线:boundaryViews
结尾。比如商品分类数据源。categoriesCell
结尾。比如 MyProfileCellDelegate
或者 Datasource
结尾。比如 XQScanViewDelegate有时候我们需要为我们创建的类设置一些注释。我们可以在类的下面添加。
枚举的命名和类的命名相近。
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 之后空一格,括号,里面的 线程修饰词、内存修饰词、读写修饰词,空一格 类 对象名称
根据不同的场景选择合适的修饰符。
@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 掉。
单例的使用场景概括如下:
+ (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,当有更新的情况下按照下面的依据
版本号 | 右说明对齐标题 | 示例 |
---|---|---|
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等的文件模版的存放文件夹地址后,我们就可以设想下我们是否可以定制自己团队风格的控制器模版、是否可以打造和维护自己团队的高频使用的代码块?
答案是可以的。
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 脚本。几个关键步骤:
我们观察系统文件模版的特点,和在 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、UIView4个模版,都以为 Power 开头。
如何共享
以 shell 脚本为工具。使用脚本将 git 云端的代码模版同步到本地 Xcode 文件夹对应的位置就可以使用了。关键步骤:
chmod +x ./syncSnippets.sh // 为脚本设置可执行权限chmod +x ./uploadMySnippets.sh // 为脚本设置可执行权限./syncSnippets.sh // 同步git云端代码块和文件模版到本地./uploadMySnippets.sh //将本地的代码块和文件模版同步到云端
不断完善中。大家有好用或者不错的代码块或者文件模版希望参与到这个项目中来,为我们开发效率的提升添砖加瓦、贡献力量
目前新建了大概58个代码段和6个类文件模版(UIViewController控制器带有方法组、模型、线程安全的单例模版、带有布局方法的UIView模版、UITableViewCell、UICollectionViewCell模版)
shell 脚本基本有每个函数和关键步骤的代码注释,想学习 shell 的人可以看看代码。代码传送门
转载地址:http://ttkki.baihongyu.com/