mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 04:17:17 +00:00
docs: SSL/TLS
This commit is contained in:
@@ -1,48 +1,59 @@
|
||||
# 开发效率提升利器
|
||||
|
||||
|
||||
> 软件的生命周期贯穿产品的开发,测试,生产,用户使用,版本升级和后期维护等过程,只有易读,易维护的软件代码才具有生命力。
|
||||
|
||||
|
||||
|
||||
## 一、思路
|
||||
|
||||
最近重构项目组件,看到项目中存在一些命名和方法分块方面存在一些问题,结合平时经验和 [Apple官方代码规范](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html) 在此整理出 iOS 工程规范。提出第一个版本,如果后期觉得有不完善的地方,继续提出来不断完善,文档在此记录的目的就是为了大家的代码可读性较好,后来的人或者团队里面的其他人看到代码可以不会因为代码风格和可读性上面造成较大时间的开销。
|
||||
|
||||
先梳理出规范,然后使用一些脚本的方式,提高大家使用的便捷性与效率,最后开发一些协作脚本。
|
||||
|
||||
|
||||
|
||||
## 二、一些原则
|
||||
|
||||
1. 长的,描述性的方法和变量命名是好的。不要使用简写,除非是一些大家都知道的场景比如 VIP。不要使用 bgView,推荐使用 backgroundView
|
||||
|
||||
2. 见名知意。含义清楚,做好不加注释代码自我表述能力强。(前提是代码足够规范)
|
||||
|
||||
3. 不要过分追求技巧,降低代码可读性
|
||||
|
||||
4. 删除没必要的代码。比如我们新建一个控制器,里面会有一些不会用到的代码,或者注释起来的代码,如果这些代码不需要,那就删除它,留着偷懒吗?下次需要自己手写
|
||||
|
||||
5. 在方法内部不要重复计算某个值,适当的情况下可以将计算结果缓存起来
|
||||
|
||||
6. 尽量减少单例的使用。
|
||||
|
||||
7. 提供一个统一的数据管理入口,不管是 MVC、MVVM、MVP 模块内提供一个统一的数据管理入口会使得代码变得更容易管理和维护。
|
||||
|
||||
8. 除了 .m 文件中方法,其他的地方"{"不需要另起一行。
|
||||
```Objective-c
|
||||
```Objective-c
|
||||
- (void)getGooodsList
|
||||
{
|
||||
{
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doHomework
|
||||
{
|
||||
{
|
||||
if (self.hungry) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
if (self.thirsty) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
if (self.tired) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
papapa.then.over;
|
||||
}
|
||||
```
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
### 变量
|
||||
|
||||
@@ -58,80 +69,87 @@
|
||||
### 条件表达式
|
||||
|
||||
1. 当有条件过多、过长的时候需要换行,为了代码看起来整齐些
|
||||
```
|
||||
//good
|
||||
if (condition1() &&
|
||||
|
||||
```
|
||||
//good
|
||||
if (condition1() &&
|
||||
condition2() &&
|
||||
condition3() &&
|
||||
condition4()) {
|
||||
// Do something
|
||||
}
|
||||
//bad
|
||||
if (condition1() && condition2() && condition3() && condition4()) { // Do something }
|
||||
```
|
||||
// Do something
|
||||
}
|
||||
//bad
|
||||
if (condition1() && condition2() && condition3() && condition4()) { // Do something }
|
||||
```
|
||||
2. 在一个代码块里面有个可能的情况时善于使用 `return` 来结束异常的情况。
|
||||
```
|
||||
```
|
||||
- (void)doHomework
|
||||
{
|
||||
{
|
||||
if (self.hungry) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
if (self.thirsty) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
if (self.tired) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
papapa.then.over;
|
||||
}
|
||||
```
|
||||
}
|
||||
```
|
||||
3. 每个分支的实现都必须使用 {} 包含。
|
||||
```
|
||||
// bad
|
||||
if (self.hungry) self.eat()
|
||||
// good
|
||||
if (self.hungry) {
|
||||
|
||||
```
|
||||
// bad
|
||||
if (self.hungry) self.eat()
|
||||
// good
|
||||
if (self.hungry) {
|
||||
self.eat()
|
||||
}
|
||||
```
|
||||
}
|
||||
```
|
||||
4. 条件判断的时候应该是变量在左,条件在右。 if ( currentCursor == 2 ) { //... }
|
||||
5. switch 语句后面的每个分支都需要用大括号括起来。
|
||||
6. switch 语句后面的 default 分支必须存在,除非是在对枚举进行 switch。
|
||||
```
|
||||
switch (menuType) {
|
||||
case menuTypeLeft: {
|
||||
|
||||
```
|
||||
switch (menuType) {
|
||||
case menuTypeLeft: {
|
||||
...
|
||||
break;
|
||||
}
|
||||
case menuTypeRight: {
|
||||
case menuTypeRight: {
|
||||
...
|
||||
break;
|
||||
}
|
||||
case menuTypeTop: {
|
||||
}
|
||||
case menuTypeTop: {
|
||||
...
|
||||
break;
|
||||
}
|
||||
case menuTypeBottom: {
|
||||
}
|
||||
case menuTypeBottom: {
|
||||
...
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 类名
|
||||
|
||||
1. 大写驼峰式命名。每个单词首字母大写。比如「申请记录控制器」ApplyRecordsViewController
|
||||
2. 每个类型的命名以该类型结尾。
|
||||
- ViewController:使用 `ViewController` 结尾。例子:ApplyRecordsViewController
|
||||
- View:使用 `View` 结尾。例子:分界线:boundaryView
|
||||
- NSArray:使用 `s` 结尾。比如商品分类数据源。categories
|
||||
- UITableViewCell:使用 `Cell` 结尾。比如 MyProfileCell
|
||||
- Protocol:使用 `Delegate` 或者 `Datasource` 结尾。比如 XQScanViewDelegate
|
||||
- Tool:工具类
|
||||
- 代理类:Delegate
|
||||
- Service 类:Service
|
||||
- ViewController:使用 `ViewController` 结尾。例子:ApplyRecordsViewController
|
||||
- View:使用 `View` 结尾。例子:分界线:boundaryView
|
||||
- NSArray:使用 `s` 结尾。比如商品分类数据源。categories
|
||||
- UITableViewCell:使用 `Cell` 结尾。比如 MyProfileCell
|
||||
- Protocol:使用 `Delegate` 或者 `Datasource` 结尾。比如 XQScanViewDelegate
|
||||
- Tool:工具类
|
||||
- 代理类:Delegate
|
||||
- Service 类:Service
|
||||
|
||||
### 类的注释
|
||||
|
||||
@@ -140,6 +158,7 @@ switch (menuType) {
|
||||
### 枚举
|
||||
|
||||
枚举的命名和类的命名相近。
|
||||
|
||||
```
|
||||
typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
UIControlContentVerticalAlignmentCenter = 0,
|
||||
@@ -176,6 +195,7 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
单例适合全局管理状态或者事件的场景。一旦创建,对象的指针保存在静态区,单例对象在堆内存中分配的内存空间只有程序销毁的时候才会释放。基于这种特点,那么我们类似 UIApplication 对象,需要全局访问唯一一个对象的情况才适合单例,或者访问频次较高的情况。我们的功能模块的生命周期肯定小于 App 的生命周期,如果多个单例对象的话,势必 App 的开销会很大,糟糕的情况系统会杀死 App。如果觉得非要用单例比较好,那么注意需要在合适的场合 tearDown 掉。
|
||||
|
||||
单例的使用场景概括如下:
|
||||
|
||||
- 控制资源的使用,通过线程同步来控制资源的并发访问。
|
||||
- 控制实例的产生,以达到节约资源的目的。
|
||||
- 控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。
|
||||
@@ -188,7 +208,7 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
//because has rewrited allocWithZone use NULL avoid endless loop lol.
|
||||
_sharedInstance = [[super allocWithZone:NULL] init];
|
||||
});
|
||||
|
||||
|
||||
return _sharedInstance;
|
||||
}
|
||||
|
||||
@@ -216,18 +236,13 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 私有变量
|
||||
|
||||
推荐以 `_` 开头,写在 .m 文件中。例如 NSString * _somePrivateVariable
|
||||
|
||||
|
||||
|
||||
### 代理方法
|
||||
### 代理方法
|
||||
|
||||
1. 类的实例必须作为方法的参数之一。
|
||||
2. 对于一些连续的状态的,可以加一些 will(将要)、did(已经)
|
||||
@@ -239,8 +254,6 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 方法
|
||||
|
||||
1. 方法与方法之间间隔一行
|
||||
@@ -268,28 +281,28 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
period:(NSInteger)second
|
||||
score:(NSInteger)score;
|
||||
```
|
||||
|
||||
11. 方法如果有多个参数的情况下需要注意是否需要介词和连词。很多时候在不知道如何抉择测时候思考下苹果的一些 API 的方法命名。
|
||||
```objective-c
|
||||
//good
|
||||
```objective-c
|
||||
//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;
|
||||
```
|
||||
```
|
||||
12. `.m` 文件中的私有方法需要在顶部进行声明
|
||||
13. 方法组之间也有个顺序问题。
|
||||
- 在文件最顶部实现属性的声明、私有方法的声明(很多人省去这一步,问题不大,但是蛮多第三方的库都写了,看起来还是会很方便,建议书写)。
|
||||
- 在生命周期的方法里面,比如 viewDidLoad 里面只做界面的添加,而不是做界面的初始化,所有的 view 初始化建议放在 getter 里面去做。往往 view 的初始化的代码长度会比较长、且一般会有多个 view 所以 getter 和 setter 一般建议放在最下面,这样子顶部就可以很清楚的看到代码的主要逻辑。
|
||||
- 所有button、gestureRecognizer 的响应事件都放在这个区域里面,不要到处乱放。
|
||||
|
||||
|
||||
|
||||
文件基本上就是
|
||||
|
||||
```objective-c
|
||||
//___FILEHEADER___
|
||||
|
||||
@@ -320,7 +333,7 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
@@ -332,13 +345,13 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -366,8 +379,6 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
@end
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 图片资源
|
||||
|
||||
1. 单个文件的命名
|
||||
@@ -377,8 +388,6 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
2. 资源的文件夹命名
|
||||
最好也参考 App 按照功能模块建立对应的实体文件夹目录,最后到对应的目录下添加相应的资源文件。
|
||||
|
||||
|
||||
|
||||
### 注释
|
||||
|
||||
1. 对于类的注释写在当前类文件的顶部
|
||||
@@ -391,11 +400,11 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
|
||||
采用 A.B.C 三位数字命名,比如:1.0.2,当有更新的情况下按照下面的依据
|
||||
|
||||
| 版本号 | 右说明对齐标题 | 示例 |
|
||||
| :------:| :------: | :------: |
|
||||
| **A**.b.c | 属于重大内容的更新 | 1.0.2 -> 2.0.0 |
|
||||
| 版本号 | 右说明对齐标题 | 示例 |
|
||||
|:---------:|:----------:|:--------------:|
|
||||
| **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 |
|
||||
| a.b.**C** | 属于补丁更新 | 1.0.2 -> 1.0.3 |
|
||||
|
||||
### 改进
|
||||
|
||||
@@ -406,74 +415,64 @@ typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
|
||||
Xcode 代码块的存放地址:`~/Library/Developer/Xcode/UserData/CodeSnippets`
|
||||
Xcode 文件模版的存放地址:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/File Templates/
|
||||
|
||||
|
||||
|
||||
### 意义
|
||||
|
||||
1. 为了个人或者团队开发者的代码更加规范。Property的书写的时候的空格、线程修饰词、内存修饰词的先后顺序
|
||||
2. 提供大量可用的代码块,提高开发效率。比如在 Xcode 里面敲 UITableView_init 便可以自动懒加载创建一个 UITabelView 对象,你只需要设置在指定的位置写相应的参数
|
||||
3. 通过一些代码块提高代码规范、避免一些bug。比如曾看到过 block 属性用 strong 修饰的代码,造成内存泄漏。举个例子你在 Xcode 中输入 **Property_delegate** 就会出来 `@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。用法见下
|
||||
|
||||
|
||||
方案:先在团队内召开代码规范会议,大家都统一知道这个事情在。之后大家共同维护 codesnippets。用法见下
|
||||
|
||||
属性:通过 **Property_类型** 开头,回车键自动补全。比如 Strong 类型,编写代码通过 Property_Strong 回车键自动补全成如下格式
|
||||
|
||||
```objective-c
|
||||
@property (nonatomic, strong) <#Class#> *<#object#>;
|
||||
```
|
||||
```objective-c
|
||||
@property (nonatomic, strong) <#Class#> *<#object#>;
|
||||
```
|
||||
|
||||
方法:以 **Method_关键词** 回车键确认,自动补全。比如 Method_UIScrollViewDelegate 回车键自动补全成 如下格式
|
||||
|
||||
```objective-c
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
|
||||
}
|
||||
```
|
||||
```objective-c
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
各种常见的 Mark:以 **Mark_关键词** 回车确认,自动补全。比如 Method_MethodsGroup 回车键自动补全成 如下格式
|
||||
|
||||
```objective-c
|
||||
#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
|
||||
```
|
||||
```objective-c
|
||||
#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”为例
|
||||
|
||||

|
||||
@@ -492,28 +491,22 @@ Xcode 文件模版的存放地址:/Applications/Xcode.app/Contents/Developer/P
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
思考:
|
||||
|
||||
- 如何使用
|
||||
|
||||
|
||||
商量好一个标识(“Power”)。比如我新建了单例、控制器、Model、UIView、UITableViewCell、UICollectionViewCell6个模版,都以为 Power 开头。
|
||||
|
||||
|
||||

|
||||
|
||||
- 如何共享
|
||||
|
||||
|
||||
以 shell 脚本为工具。使用脚本将 git 云端的代码模版同步到本地 Xcode 文件夹对应的位置就可以使用了。关键步骤:
|
||||
|
||||
|
||||
1. git clone 代码到脚本所在文件夹
|
||||
2. 进入存放 codesnippets 的文件夹将内容复制到系统存放 codesnippets 的地方
|
||||
3. 进入存放 file template 的文件夹将内容复制到系统存放 file template 的地方
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 六、使用
|
||||
|
||||
### 1. Xcode 中开发
|
||||
@@ -542,8 +535,6 @@ Xcode 文件模版的存放地址:/Applications/Xcode.app/Contents/Developer/P
|
||||
|
||||
- 一些常用的代码块。敲 **Thread_** 等自动联想,选中后敲回车自动补全。
|
||||
|
||||
|
||||
|
||||
### 2. Code Snippet 同步
|
||||
|
||||
你可能是代码块的创建者,也可能是使用方,使用的时候直接先给脚本赋权
|
||||
@@ -560,7 +551,6 @@ chmod +x ./uploadMySnippets.sh // 为脚本设置可执行权限
|
||||
./uploadMySnippets.sh //将本地的代码块和文件模版同步到云端
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Reference in New Issue
Block a user