<commit_before>---
layout:     post
title:      小团队的iOS代码规范
subtitle:   在不断填坑中前进。。
date:       2017-08-11
author:     三十一
header-img: img/post-bg-nextgen-web-pwa.jpg
header-mask: 0.3
catalog:    true
tags:
   - 
---
[TOC]
# 小团队的iOS代码规范

本文摘抄自<a font="24px">[iOS 代码规范](https://knightsj.github.io/2017/06/14/iOS%20%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83/#more)</a>，稍加修改。

### 1 核心原则
#### 1.1 代码应该简洁易懂，逻辑清晰
因为软件是需要人来维护的。这个人在未来很可能不是你。所以首先是为人编写程序，其次才是计算机：

* 不要过分追求技巧，降低程序的可读性。
* 简洁的代码可以让bug无处藏身。要写出明显没有bug的代码，而不是没有明显bug的代码。

#### 1.2 编程时首先达到正确性，其次考虑效率
在正确可用的代码写出之前就过度地考虑扩展，重用的问题，使得工程过度复杂。

1. 先把眼前的问题解决掉，解决好，再考虑将来的扩展问题。
2. 先写出可用的代码，反复推敲，再考虑是否需要重用的问题。
3. 先写出可用，简单，明显没有bug的代码，再考虑测试的问题。

#### 1.3 面向变化编程，而不是面向需求编程

**不要相信产品说的话，要时刻做好需求会改的准备。**
**不要相信产品说的话，要时刻做好需求会改的准备。**
**不要相信产品说的话，要时刻做好需求会改的准备。**

每次迭代不能仅仅为了当前的需求，写出扩展性强，易修改的程序才是负责任的做法，对自己负责，对公司负责。
### 2 具体规范
#### 2.1 变量、属性
##### 2.1.1 命名必须使用驼峰格式
类，协议使用大驼峰

```
HomePageViewController.h
<HeaderViewDelegate>
```
对象等局部变量使用小驼峰：

```
NSString *personName = @"";
NSUInteger totalCount = 0;
```
##### 2.1.2 变量的名称必须同时包含功能与类型

```
UIButton *addBtn //添加按钮
UILabel *nameLbl //名字标签
NSString *addressStr//地址字符串
```
##### 2.1.3 系统常用类作实例变量声明时加入后缀

| 类型 | 后缀 |
| --- | --- |
| UIViewController | VC |
| UIView | View |
| UILabel | Lbl |
| UIButton | Btn |
| UIImage | Img |
| UIImageView | ImagView |
| NSArray | Array |
| NSMutableArray|  Marray|
| NSDictionary  | Dict |
| NSMutableDictionary  | Mdict  |
| NSString | Str |
| NSMutableString| MStr |
| NSSet |  Set |
| NSMutableSet  | Mset |

##### 2.1.3 下划线不应出现在局部变量
推荐：

```
NSDictionary *notificationInfo;
```

不推荐：

```
NSDictionary *_notificationInfo;
```

##### 2.1.4 定义指针类型的变量
定义指针类型的变量时,`*`放在变量前，与类型保持一个空格。
推荐：

```
NSDictionary *notificationInfo;
```

不推荐：

```
NSDictionary*notificationInfo;
NSDictionary* notificationInfo;
NSDictionary * notificationInfo;
```

##### 2.1.5 不要出现仅依靠大小写区分的命名
程序中不要出现仅靠大小区分的相似的标识符。
不推荐：

```
NSDictionary *notificationInfo;
NSDictionary *NotificationInfo;
```
##### 2.1.6 私有属性应放到匿名分类中

```
@interface RWTDetailViewController ()  
@property (strong, nonatomic) GADBannerView *googleAdView;  
@property (strong, nonatomic) ADBannerView *iAdView;  
@property (strong, nonatomic) UIWebView *adXWebView;  
@end
```
##### 2.1.7 形容词性的BOOL属性的getter应该加上is前缀

```
@property (assign, getter=isEditable) BOOL editable;
```
##### 2.1.8 使用getter方法做懒加载

实例化一个对象是需要耗费资源的，如果这个对象里的某个属性的实例化要调用很多配置和计算，就需要懒加载它，在使用它的前一刻对它进行实例化：

```
//推荐这样写
@property(nonatomic,strong)UIView *demoView;

- (UIView *)demoView{
    if (_demoView == nil) {
        _demoView = ({
            UIView *view = [[UIView alloc] initWithFrame:self.view.bounds];
            view.backgroundColor = [UIColor redColor];
            view.alpha = 0.8f;
            view;
        });
    }
    
    return _demoView;
}
```

但是也有对这种做法的争议，但是整体利大于弊，推荐使用。
##### 2.1.9 除了init和dealloc方法，建议都使用点语法访问属性

使用点语法的好处：
setter：

1. setter会遵守内存管理语义(strong, copy, weak)。
2. 通过在内部设置断点，有助于调试bug。
3. 可以过滤一些外部传入的值。
4. 捕捉KVO通知。

getter：

1. 允许子类化。
2. 通过在内部设置断点，有助于调试bug。
3. 实现懒加载（lazy initialization）。


**注意：**

* 懒加载的属性，必须通过点语法来读取数据。因为懒加载是通过重写getter方法来初始化实例变量的，如果不通过属性来读取该实例变量，那么这个实例变量就永远不会被初始化。
* 在init和dealloc方法里面使用点语法的后果是：因为没有绕过setter和getter，在setter和getter里面可能会有很多其他的操作。而且如果它的子类重载了它的setter和getter方法，那么就可能导致该子类调用其他的方法。

##### 2.1.10 属性声明严把权限

对不需要外部修改的属性使用readonly。
##### 2.1.11 尽量使用不可变对象
建议尽量把对外公布出来的属性设置为只读，在实现文件内部设为读写。具体做法是：

- 在头文件中，设置对象属性为 `readonly`
- 在实现文件中设置为 `readwrite`。

<commit_msg>小团队的iOS代码规范-函数<commit_after>---
layout:     post
title:      小团队的iOS代码规范
subtitle:   在不断填坑中前进。。
date:       2017-08-11
author:     三十一
header-img: img/post-bg-nextgen-web-pwa.jpg
header-mask: 0.3
catalog:    true
tags:
   - 
---
[TOC]
# 小团队的iOS代码规范

本文摘抄自<a font="24px">[iOS 代码规范](https://knightsj.github.io/2017/06/14/iOS%20%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83/#more)</a>，稍加修改。

### 1 核心原则
#### 1.1 代码应该简洁易懂，逻辑清晰
因为软件是需要人来维护的。这个人在未来很可能不是你。所以首先是为人编写程序，其次才是计算机：

* 不要过分追求技巧，降低程序的可读性。
* 简洁的代码可以让bug无处藏身。要写出明显没有bug的代码，而不是没有明显bug的代码。

#### 1.2 编程时首先达到正确性，其次考虑效率
在正确可用的代码写出之前就过度地考虑扩展，重用的问题，使得工程过度复杂。

1. 先把眼前的问题解决掉，解决好，再考虑将来的扩展问题。
2. 先写出可用的代码，反复推敲，再考虑是否需要重用的问题。
3. 先写出可用，简单，明显没有bug的代码，再考虑测试的问题。

#### 1.3 面向变化编程，而不是面向需求编程

**不要相信产品说的话，要时刻做好需求会改的准备。**
**不要相信产品说的话，要时刻做好需求会改的准备。**
**不要相信产品说的话，要时刻做好需求会改的准备。**

每次迭代不能仅仅为了当前的需求，写出扩展性强，易修改的程序才是负责任的做法，对自己负责，对公司负责。
### 2 具体规范
#### 2.1 变量、属性
##### 2.1.1 命名必须使用驼峰格式
类，协议使用大驼峰

```
HomePageViewController.h
<HeaderViewDelegate>
```
对象等局部变量使用小驼峰：

```
NSString *personName = @"";
NSUInteger totalCount = 0;
```
##### 2.1.2 变量的名称必须同时包含功能与类型

```
UIButton *addBtn //添加按钮
UILabel *nameLbl //名字标签
NSString *addressStr//地址字符串
```
##### 2.1.3 系统常用类作实例变量声明时加入后缀

| 类型 | 后缀 |
| --- | --- |
| UIViewController | VC |
| UIView | View |
| UILabel | Lbl |
| UIButton | Btn |
| UIImage | Img |
| UIImageView | ImagView |
| NSArray | Array |
| NSMutableArray|  Marray|
| NSDictionary  | Dict |
| NSMutableDictionary  | Mdict  |
| NSString | Str |
| NSMutableString| MStr |
| NSSet |  Set |
| NSMutableSet  | Mset |

##### 2.1.3 下划线不应出现在局部变量
推荐：

```
NSDictionary *notificationInfo;
```

不推荐：

```
NSDictionary *_notificationInfo;
```

##### 2.1.4 定义指针类型的变量
定义指针类型的变量时,`*`放在变量前，与类型保持一个空格。
推荐：

```
NSDictionary *notificationInfo;
```

不推荐：

```
NSDictionary*notificationInfo;
NSDictionary* notificationInfo;
NSDictionary * notificationInfo;
```

##### 2.1.5 不要出现仅依靠大小写区分的命名
程序中不要出现仅靠大小区分的相似的标识符。
不推荐：

```
NSDictionary *notificationInfo;
NSDictionary *NotificationInfo;
```
##### 2.1.6 私有属性应放到匿名分类中

```
@interface RWTDetailViewController ()  
@property (strong, nonatomic) GADBannerView *googleAdView;  
@property (strong, nonatomic) ADBannerView *iAdView;  
@property (strong, nonatomic) UIWebView *adXWebView;  
@end
```
##### 2.1.7 形容词性的BOOL属性的getter应该加上is前缀

```
@property (assign, getter=isEditable) BOOL editable;
```
##### 2.1.8 使用getter方法做懒加载

实例化一个对象是需要耗费资源的，如果这个对象里的某个属性的实例化要调用很多配置和计算，就需要懒加载它，在使用它的前一刻对它进行实例化：

```
//推荐这样写
@property(nonatomic,strong)UIView *demoView;

- (UIView *)demoView{
    if (_demoView == nil) {
        _demoView = ({
            UIView *view = [[UIView alloc] initWithFrame:self.view.bounds];
            view.backgroundColor = [UIColor redColor];
            view.alpha = 0.8f;
            view;
        });
    }
    
    return _demoView;
}
```

但是也有对这种做法的争议，但是整体利大于弊，推荐使用。
##### 2.1.9 除了init和dealloc方法，建议都使用点语法访问属性

使用点语法的好处：
setter：

1. setter会遵守内存管理语义(strong, copy, weak)。
2. 通过在内部设置断点，有助于调试bug。
3. 可以过滤一些外部传入的值。
4. 捕捉KVO通知。

getter：

1. 允许子类化。
2. 通过在内部设置断点，有助于调试bug。
3. 实现懒加载（lazy initialization）。


**注意：**

* 懒加载的属性，必须通过点语法来读取数据。因为懒加载是通过重写getter方法来初始化实例变量的，如果不通过属性来读取该实例变量，那么这个实例变量就永远不会被初始化。
* 在init和dealloc方法里面使用点语法的后果是：因为没有绕过setter和getter，在setter和getter里面可能会有很多其他的操作。而且如果它的子类重载了它的setter和getter方法，那么就可能导致该子类调用其他的方法。

##### 2.1.10 属性声明严把权限

对不需要外部修改的属性使用readonly。
##### 2.1.11 尽量使用不可变对象
建议尽量把对外公布出来的属性设置为只读，在实现文件内部设为读写。具体做法是：

- 在头文件中，设置对象属性为 `readonly`
- 在实现文件中设置为 `readwrite`。

#### 2.2 函数
##### 2.2.1 函数保持单一性
函数是为一特定功能而编写，不是万能工具箱，保持单一性，一个函数只做一件事情。
##### 2.2.2 函数名与形参不能留空格，返回类型与函数标识符有一个空格

```
- (void)someMethod;
```
##### 2.2.3 如果参数过长，则每个参数一行，以冒号对齐。

```
- (void)someMethod:(id)parameter
        parameter1:(id)parameter1
        parameter2:(id)parameter2;
```
##### 2.2.4 如果函数名比参数名短，则每个参数占用一行,垂直对齐（非冒号对齐）
```
- (void)someMethod:(id)parameter
        a:(id)parameter1
        b:(id)parameter2;
```
##### 2.2.5 函数名用小写字母开头的单词组合而成

函数名力求清晰、明了、通过函数名就能够判断函数的主要功能。函数名中不同意义字段之间不要用下划线连接，而要把每个字段的首字母大写以示区分。

推荐

```

- (NSString *)descriptionWithLocale:(id)locale;
- 
```

不推荐

```
- (NSString *)DescriptionWithLocale:(id)locale;
- (NSString *)description_locale:(id)locale;
```
##### 2.2.6 避免函数有太多的参数，参数个数尽量控制在5个以内
如果参数的确比较多，考虑这些参数定义成一个结构（或一个类）。
##### 2.2.7 对输入参数的正确性和有效性进行检查
很多程序错误和崩溃是由非法参数引起的。对外提供的函数接口，一定要检查输入参数。
对输入参数的正确性和有效性进行检查，参数错误立即返回。

```
void function(param1,param2)
{
      if(param1 is unavailable){
           return;
      }
    
      if(param2 is unavailable){
           return;
      }
     //Do some right thing
}
```
##### 2.2.8 函数（方法）体的规模不能太大
函数（方法）体的规模不能太大，尽量控制在可以在一屏幕内显示。
##### 2.2.9 对于有返回值的函数（方法），每一个分支都必须有返回值

推荐

```
int function()
{
    if(condition1){
        return count1
    }else if(condition2){
        return count2
    }else{
       return defaultCount
    } 
}
```
不推荐

```
int function()
{
    if(condition1){
        return count1
    }else if(condition2){
        return count2
    }
}
```
##### 2.2.10 如果在不同的函数内部有相同的功能
如果在不同的函数内部有相同的功能，应该把相同的功能抽取出来单独作为另一个函数
##### 2.2.11 方法名前缀

* 刷新视图的方法名要以 `refresh` 为首。
* 更新数据的方法名要以 `update` 为首。

```
- (void)refreshHeaderViewWithCount:(NSUInteger)count;

- (void)updateDataSourceWithViewModel:(ViewModel *)viewModel;
```
##### 2.2.12 函数之间保留一个空行
推荐

```
- (void)refreshHeaderViewWithCount:(NSUInteger)count;

- (void)updateDataSourceWithViewModel:(ViewModel *)viewModel;

- (void)refreshHeaderViewWithCount:(NSUInteger)count
{
}

- (void)updateDataSourceWithViewModel:(ViewModel *)viewModel
{
}
```

##### 2.2.13 初始化方法
初始化方法返回类型必须是instancetype，不能是id。

```
- (instancetype)init { 
    self = [super init]; // call the designated initializer 
    if (self) { 
        // Custom initialization 
    } 
    return self; 
}
```


{'fraction_non_alphanumeric': 0.16046128500823723, 'fraction_numerical': 0.028336079077429983, 'mean_word_length': 4.652389819987586, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6432107', 'n_tokens_mistral': 5666, 'n_tokens_neox': 5979, 'n_words': 554}