开发规范

241 阅读11分钟

iOS开发

为了利于项目维护以及规范开发,促进成员之间Code Review的效率,故提出以下开发规范,如有更好的建议,欢迎提出。本文档的预期读者包括:iOS开发人员。

命名规范

代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。正确的英文拼写和语法可以让阅读者易于理解,避免歧义。
*注意:即使纯拼音命名方式也要避免采用。但alibab、taobao、youku、hangzhou等国际通用的名称,可视同英文.

大驼峰规则:每个单词的首字母大写。例:NameTextField。
小驼峰原则:第一个单词首字母小写,其余都大写。例:nameTextField。

项目命名

项目名都遵循大驼峰命名。例如:MpmYEB

Bundle Identifier 命名

Bundle Identifier:采用反域名命名规范,全部采用小写字母,以域名后缀+公司顶级域名+应用名形式命名,例如:com.hzmpm.yebstoreproduct

类名

类的命名都遵循大驼峰命名。一般是:前缀 + 功能 + 类型。例如:MPM + Login + ViewController

在实际开发中,一般都会给工程中所有的类加上属于本工程的前缀。

常用控件类命名类型对照表(下表中前缀为:MPM,如果用到下表中没有列举出来,请去掉UI首字母,遵循实际规则即可。)

控件名类型示例
UIViewControllerViewControllerMPMBaseViewController
UIViewViewMPMBaseView
UITableViewTableViewMPMOrderTableView
UITableViewCellCellMPMOrderListCell
UIButtonButtonMPMSuccessButton
UILabelLabelMPMSuccessLabel
UIImageViewImgViewMPMGoodsImgView
UITextFieldTextFieldMPMNameTextField
UITextViewTextViewMPMSuggestTextView

其它类相关对照表

功能类型示例
工具类ToolMPMOrderTool
代理类DelegateMPMOrderListDelegate
管理类ManagerMPMOrderListModel
模型类ModelMPMOrderListModel
Service类ServiceMPMOrderService
布局类LayoutMPMHomeLayout
数据库类DataBase、表名+DBHelperMPMFriendDataBase、MPMUserTableDBHelper
类目XXX+(范围,例如Extension, Additions 或者功能,例如Frame,Nib,Block)MPMUIButton+Additions、MPMUIButton+Block

UIViewController请按照如下分类

#pragma mark - life cycle
#pragma mark - event response
#pragma mark - UITableViewDelegate && UITableViewDataSource
(代理顺序往下排列)
#pragma mark - getters and setters
#pragma mark - private

注意:所有视图或者对象的创建请尽量使用懒加载,调用的时候全部使用self.textBtn这样的方式。如果是确定的不可变数组、字典,可直接给定数组中的元素。(getters and setters分类中,懒加载可出现_调用对象,其它情况请遵循self.调用原则)

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, strong) UIButton * textBtn;
@end

@implementation ViewController

#pragma mark - life cycle
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.textBtn];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
#pragma mark - private 

#pragma mark - event response

#pragma mark - UITableViewDelegate && UITableViewDataSource
//(代理顺序往下排列)

#pragma mark - CTAPIManagerCallBackDelegate

#pragma mark - getters and setters
- (UIButton *)textBtn
{
    if (_textBtn == nil) {
        _textBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        _textBtn.frame = CGRectMake(300, 250, 100, 100);
        _textBtn.backgroundColor = [UIColor yellowColor];
        _textBtn.titleLabel.text = @"text";
        [_textBtn addTarget:self action:@selector(text) forControlEvents:UIControlEventTouchUpInside];
    }
    return _textBtn;
}
@end

变量和方法

变量和方法的命名都遵循小驼峰命名。例如:textVariableStr- (void)textAction响应事件。
变量命名对照表(如果用到下表中没有列举出来,请去掉UINS遵循实际规则即可。或者一看就知道的通用简写)
方法命名对照表(方法多为动词或动名词)

功能示例
- (id)initXX初始化相关方法,使用init为前缀标识,如初始化布局- (id)initView
- (BOOL)isXX方法返回值为boolean型的请使用is前缀标识
- (UIView *)getXX返回某个值的方法,使用get为前缀标识
- (void)setXX设置某个属性值或者相关数据
- (void)updateXX更新数据
- (void)saveXX保存数据
- (void)drawXX绘制相关,使用draw前缀标识
- (void)clearXX清除数据
- (void)XXXAction响应事件,使用Action为后缀标识
- (void)loadData加载数据(一般情况下VC中都会有这个方法)
- (void)loadMoreData加载更多数据
- (void)setupUI加载布局(一般情况下VC中都会有这个方法)

方法

  1. 前括号提至方法后
  2. 同一模块功能代码写在一起
  3. 不同模块功能换行写
- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    [self setupHeadView];
    [self setupTableView];
    
    [self getCellDatas];
}

常量

宏:小写k+大驼峰 即为:#define kUserAgeKey @“ageKey”
全局常量:工程前缀全大写,下划线隔开 即为:extern const NSString MPM_USER_AGE_KEY

枚举常量

【必须】使用枚举类型来表示一组相关的整型常量。

【建议】枚举常量和typedef定义的枚举类型的命名规范同函数的命名规范一致。

typedef enum _NSMatrixMode {
    NSRadioModeMatrix           = 0,
    NSHighlightModeMatrix       = 1,
    NSListModeMatrix            = 2,
    NSTrackModeMatrix           = 3
} NSMatrixMode;

注意:上面枚举typeof中的_NSMatrixMode是无用的。 我们可以像位掩码(bit masks)一样创建一个匿名枚举,如下:

enum {
    NSBorderlessWindowMask      = 0,
    NSTitledWindowMask          = 1 << 0,
    NSClosableWindowMask        = 1 << 1,
    NSMiniaturizableWindowMask  = 1 << 2,
    NSResizableWindowMask       = 1 << 3
};

参数名

参数名以小驼峰命名,尽量参考苹果原生方法风格编写。尽量可读性好,看到方法名就知道这个方法是用来干什么的。参数应该避免用单个字符命名。例:- (void)setDataImageUrl:(NSString *)imageUrl name:(NSString *)nameStr content:(NSString *)contentStr

资源文件命名

全部小写,采用下划线命名法,加前缀区分。所有的资源文件都需要加上工程前缀(小写形式)
命名模式:可加后缀_small表示小图,_big表示大图,逻辑名称可由多个单词加下划线组成,采用以下规则:
用途_模块名_逻辑名称
用途_模块名_颜色
用途_逻辑名称
用途_颜色

说明前缀(工程前缀示例MPM)示例
按钮相关mpm_btn_mpm_btn_home_normal、mpm_btn_red,mpm_btn_red_big
背景相关mpm_btn_mpm_bg_home_header、mpm_bg_main
图标相关mpm_ic_mpm_ic_home_location、mpm_bg_input
分割线相关mpm_div_mpm_ic_home_location、mpm_bg_input
默认相关mpm_def_mpm_ic_home_location、mpm_bg_input

文件夹命名

创建文件夹最好创建实体文件夹,找到工程目录,创建相应文件夹并拖入工程。文件夹命名使用相应模块结构分层的英文,首字母要大写。例:ModelViewControllerToolOtherService等等。

版本规范

采用A.B.C 三位数字命名,比如:1.0.2,当有版本更新的时候,依据下面的情况来确定版本号规范。

版本号说明示例
A.b.c属于重大更新内容1.0.2 -> 2.00
a.B.c属于小部分更新内容1.0.2 -> 1.2.2
a.b.C属于补丁更新内容1.0.2 -> 1.0.4

第三方库规范

希望Team能用时下较新的技术,对开源库的选取,一般都需要选择比较稳定的版本,作者在维护的项目,要考虑作者对issue的解决,以及开发者的知名度等各方面。选取之后,一定的封装是必要的。

项目使用cocoapods统一管理开源第三库文件,不需要手动导入和手动添加依赖库。如果第三方不支持cocoapods,可手动导入工程。

注释规范

为了减少他人阅读你代码的痛苦值,请在关键地方做好注释。

类注释

//
//  MPMCustomerDebtInfoExportController.m
//  MpmYEB
//
//  Created by Done.L on 2020/11/26.
//  Copyright © 2020 MeiPingMi. All rights reserved.
//
// 导出流水弹窗

该注释是自动生成的,在xcode中设置即可。Created by 电脑用户名on 创建该文件的时间。Copyright 2020 后面的名字和邮箱是自己填写和设置的。具体可在xcode工程,Project Document中设置。这样便可在每次新建类的时候自动加上该头注释。

方法注释

方法注释,方法外部统一用option + command + /,方法内部统一用//注释。

/**
 测试
 */
- (void)test
{
    //测试按钮事件响应
}

模型注释

每个model中的,包含的每个属性,都必须要写上相对应的注释,用///注释。阅读者一看这个model,就清楚知道model中的每个字段代表的意思,用来做什么事情的。

/// 临时记录最终价(计算最终优惠使用)
@property (nonatomic, copy) NSString *tempDealPrice;
/// 取消更新价格暂存价
@property (nonatomic, copy) NSString *cancelUpdatePrice;
/// 备注
@property (nonatomic, copy) NSString *remark;
/// 是否有效
@property (nonatomic, assign) BOOL isUnable;
/// 全部失效
@property (nonatomic, assign) BOOL isAllUnable;
/// 是否显示批量按钮
@property (nonatomic, assign) BOOL isShowBatchBtn;
/// 是否是退货还是卖货
@property (nonatomic, assign) BOOL isSale;

如果不是model的属性,是其它类属性,需要注释,请按照model属性注释方式。

编码规范

  • 所有的方法之间空一行。
  • 所有的代码块之间空一行,删除多余的注释。
  • 所有自定义的方法需要给出注释。
  • 尽量使用懒加载,在控制器分类时有提及和要求,其它自定义类按照控制器格式分类,没有的分类不写即可。
  • 代码后的’{‘不需要独占一行,包括方法之后,if,switch等。
  • 必须要统一的要求,属性的定义请按照下图property之后,空一格,括号之后空一格,写上类名,空一格之后跟上*和属性名。
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) DeliveryModel *delivery;
@property (nonatomic, strong) DeliveryLookAdapter *lookAdapter;
@property (nonatomic, strong) DeliveryLookAPIManager *lookManager;
  • 遵循一般代码规范,多模仿苹果API。
  • 删除不用的代码。
  • 如果有方法一直不会用到,请删除(除工具类)。
  • 没有执行任何业务逻辑的方法,请删除或给予注释,删除多余的资源或文件,添加必要的注释。
  • 比较大的代码块需要给出注释。

其它规范

  • 建议项目统一使用Masonry方式布局。不允许出现直接设置frame的情况。如果是纯代码的项目,不允许出现xib和拉约束的情况。不建议使用纯storyboard开发。
  • 数据提供统一的入口。无论是在 MVP、MVC 还是 MVVM 中,提供一个统一的数据入口,都可以让代码变得更加易于维护。比如可使用一个DataManager,把 http、preference、eventpost、database 都放在DataManger里面进行操作,我们只需要与DataManger打交道
  • 提取方法,去除重复代码。对于必要的工具类抽取也很重要,这在以后的项目中是可以重用的。
  • 尽可能的使用局部变量
  • 尽量减少对变量的重复计算。
  • 尽量在合适的场合使用单例。使用单例可以减轻加载的负担,缩短加载的时间,提高加载效率。但并不是所有的地方都适用于单例,简单来说单例主要适用于以下三个方面:
    1. 控制资源的使用,通过线程同步来控制资源的并发访问。
    2. 控制实例的产生,以达到节约资源的目的。
    3. 控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。
  • 最后不要忘了检测内存泄漏。可使用Instruments分析内存。

代码提交规范

  • 每人维护一个自己的远端业务分支和对应的本地分支
  • 开发完对应的业务后要及时推送到自己远端,然后拉取team远端代码合并到本地,再推送到自己的远端
  • 从自己的远端找到对应的分支发起merge request到team对应的分支
  • 组内同学只能发起 merge request 不能自己合并,具体合并由组长操作
  • 每次合并都要做到code review,对于不符合规范的提出来并改正

产品

  • 开发

    1.需求文档要保证完整性,拒绝一句话需求

    2.为了需求来源性统一,合理性的需求反馈要从产品下发并worktile建立相关可溯源需求池

    3.需求要确保合理性,如遇到业务逻辑复杂的的需求务必要有详细文字描述,复杂计算务必要有步骤以及相关公式推算

    4.需求会之前,组长要提前核查一下相关需求,有不合理地方提前反馈到产品端

  • 发布

    1.不接受新增需求,保证发布稳定为前提

    2.新需求可以放入下期迭代

    3.如遇bug问题可以修改排查

UI

1.需求会议完结后,UI要和产品确定哪些页面改动会较大提前告知开发,免得开发做返工操作

2.需求会议结束后快速响应一些能给到开发的页面

3.开发过程中重复多次改动同一处UI,这种问题怎么处理?怎样减少多次改动同一个设计稿导致的耗时返工问题?

4.UI风格和相关规范尽可能和之前版本保持一致,平台差异性的尽量以各个平台风格为主

测试

1.为了提高发版效率,务必做到上了预发环境基本没有问题,只用验证部分功能有没有异常

2.提出bug要规范,备注属于哪个平台哪个版本手机还是PAD企业还是零售,尽量多描述发现的步骤,必要时留下对应环境的使用账号

3.测试过程中对于一些临时需求或者测试自己提出的需求,请告知产品,并建立相应的需求跟踪

4.按照测试用例规范化进行测试

5.不要清理开发人员的账号,除非有人离职

服务端

  • 后端编写和维护接口文档,在 API 变化时更新接口文档,并给予说明
  • 后端根据接口文档进行接口开发
  • 前端根据接口文档进行开发
  • 开发完成后联调和提交测试
前后端讨论接口-->后端整理接口文档
后端整理接口文档-->后端接口录入接口管理平台
后端开发服务接口--> 对接集成
前端对接--> 对接集成

协议规范

  • GET : 用于从服务器获取资源信息
  • POST : 用于创建新资源
  • PUT : 用于完整的替换资源或者创建指定身份的资源
  • DELETE : 用于删除某个资
  • PATCH : 用于局部更新资源

返回数据规范

截屏2021-09-27 下午2.30.37.png

状态码

状态,200成功,400失败,401登录令牌失效,402token刷新失效,403访问权限受限

前端

1.与前端交互所需字段iOS和安卓平台要约定一致

2.一些导航页面跳转遵循项目之前实现跳转交互逻辑,具体参考 CMBaseWebViewController页面

3.页面传参格式按照前端要求标准化json数据