编码风格
一般规则
1. 集合转换
从一个集合转换到另一个集合时,尽量使用map、filter、reduce和其他一些类似函数式编程操作符组合,避免使用迭代的方式。
在使用这些方法时避免使用有副作用的闭包。
2. 代理弱引用
在delegate
和protocol
中,确保生命周期,属性使用weak
。
3. 闭包弱引用
在闭包中避免循环引用
4. 类型推断
不要使用类方法的简写,因为从类方法比枚举推断上下文通常更困难。
5. 方法重写
在编写方法时,需要考虑是否需要重写,如果不需要,可以使用final
显示的标记,这样可以提高编译时间。
6. 类方法和类属性
在声明与类关联的函数或属性时,首选是static
而不是class
。
当我们需要在子类中重写该函数或方法时才使用class
。
可以考虑使用Protocol
实现这一点。
7. 计算属性
当一个函数没有参数,仅仅是返回一些对象或值,最好使用计算属性。
变量
1. let
和var
let
和var
尽量使用let
声明变量,只有当变量确实需要改变时,才需要声明为var
。
2. 属性值
如果属性的值直到被创建时才知道,那么仍然可以使用let
:在初始化期间分配常量属性。
3. 类型推导
如果常量或变量能够自动推导类型, 最好不要显示的声明类型。
4. 具有描述性
声明变量时,应该具有描述性,不需要太详细。
5. 避免重复
避免重复类型信息,一次就够了。
常量
1. 私有常量
在可能的情况下,与之相关的文件保持常量是私有的。
2. 定义常量
为代码中不变的数据定义常量。
例如:单元格复用标识符的字符串常量,key
名称(KVC 或者 字典),segue
标识符。
3. 静态常量
如果常量是在类或者结构体中声明的,则必须将其声明为static
,以避免为每个实例声明一个常量。
4. 不必使用K
前缀
K
前缀Swift
中常量不必使用K
作为前缀。
5. 文件级常量
文件级常量必须使用fileprivate let
声明。
元组
1. 函数返回值
如果一个函数返回多个值,可以使用命名元组。
如果返回类型很明显,可以省略命名。
如果一个元组中有3个或3个以上的项,需使用类或结构体替换。
2. 重定义
如果不止一次的使用某个元组,需要使用typealias
定义。
如public typealias Address = (name: String, number: Int)
访问修饰符
1. 顺序
访问修饰符必须放在声明属性之前。
2. 同一行内声明
访问修饰符关键字应该和其他代码放在一行。
3. 默认修饰符
默认修饰符为internal
,无需显示的声明。
4. 单元测试
当您需要为单元测试设置一个变量为open
时,将其标记为内部使用@testable import Module
。
如果属性应该是私有的,但是为了单元测试的目的而将其声明为内部属性,需要添加适当的文档注释。
5. 私有
尽量使用private
而不是fileprivate
。
6. 公开
如果在模块外部可以设置子类化的内容,尽量使用open
而不是public
。
自定义操作符
1. 避免自定义运算符
应该避免创建自定义运算符,防止降低代码的可读性。如果需要创建自定义运算符,可以使用命名函数替换。
2. 重写现有操作符
可以覆盖现有的操作符来支持新的类型。如使用==
比较时。
3. 更多参考
更多参考内容NSHipster article.
Switch 和 Enums
1. break
Switch语句中不存在隐式贯穿,因此不需要在 case 分支中显式地使用 break
语句。
2. default
当使用具有有限可能的Switch
语句时,不要使用default case
为未使用的case
创建一个单独的用例。
3. 对齐
case
和switch
左侧对齐
4. 关联值
当为枚举定义关联值时,一定要显式地描述它。
5. list case
优先使用list case
(如case 1, 2, 3:
)。
6. 抛出错误
当有case未执行到,需要把错误信息抛到上层而不是默认失败。
7. 避免写出枚举类型
当编译器能够自动推导出枚举类型时,则不需要写出枚举类型。
可选值
1. 避免强制解包
避免使用!
,as!
,try!
强制解包,当强制解包空内容时会引发崩溃。
2. 可选类型
当变量,函数返回值可以为nil
时,需要声明为可选类型(?
)。
3. 显示比较
当需要判断值是否为nil
又不需要解包出来的值,则可以进行显示比较。
4. 避免使用unowned
unowned
避免使用隐式解包
5. 使用相同名称解包
可以使用相同的变量名称解包
6. 多个可选绑定
在同一个if
语句中可以使用多个可选绑定,避免多重if
嵌套。
错误使用❌
正确使用✅
7. 多个可选绑定的格式
当使用if
或guard
对多个可选值进行解包时,将每个常量或变量放在一行,后面跟着一个逗号,
,最后一行除外。
当是guard
语句时,最后一行是变量后面跟着 else {
,
当是if
语句时,最后一行是变量后面跟着{
。
协议
1. 组织代码
使用
// MARK:
将协议与其他代码分开。在
class
或struct
的实现之外创建extension
,但在同一个文件内。
#2 子类不能覆盖扩展里的方法。
2. @objc
如果协议具有可选方法,则必须使用@objc
关键字声明它。
3. 多个类使用同一协议
多个类使用同一协议,请在自己的文件内声明。
4. 仅支持class的协议
若仅支持类类型的协议,需要增加class
关键字。
属性
1. 只读计算属性
创建只读计算属性,不需要增加get {}
。
2. 代码缩进
get {}
, set {}
, willSet
, didSet
必须使用代码缩进。
3. newValue,oldValue
在set
、get
方法中使用标准的newValue
,oldValue
。
4. 单例的实现
必须使用下面这种方式
5. 懒加载
使用lazy
关键字,实现懒加载,延迟对象的初始化,控制声明周期,在特殊情况下根据需要减少内存分配。
三目运算符
为了增加清晰度和代码整洁度,可适当使用三木运算符? :
。
三元运算符的最佳用途是在赋值变量和决定使用哪个值。
闭包
1. 省略类型
在闭包内声明参数,如果能够自动推导类型,也可以省略类型。
2. 行数
如果不超过一行字符的限制,则应该保持左括号和参数在同一行。
3. 简写参数
仅对简单的单行闭包实现使用简写参数语法。
对于复杂的情况,明确定义参数。
4. 尾随闭包
仅当参数列表末尾有单个闭包表达式参数时,才使用尾随闭包语法。 给出闭包参数描述性名称。
代理
1. 委托源
创建自定义代理方法时,未命名的第一个参数应该是委托源。
数组
1. 避免下标访问
避免使用下标直接访问数组,但可以使用.first
或.last
等访问器,以确保项目不可用时的安全性。 如果没有访问器,请务必先进行正确的绑定检查。
2. 迭代
使用for item in items
语法,禁止使用for i in 0 ..< items.count
。
3. 连接数组
使用.append()
或.append(contentsOf:)
方法代替+-操作符去连接数组,因为在编译阶段,它们性能更高。
guard
的使用
guard
的使用1. 尽早退出
尽早退出是对函数进行完整性检查的首选方法。也是避免嵌套if
语句的首选方法。使用guard
可以提高代码的可读性。
2. 完整性检查
免使用嵌套的if
语句并减少代码中嵌套缩进的数量:使用guard
语句而不是if
语句进行完整性检查。
3. 避免单行guard
语句
guard
语句避免在一行上使用guard
语句。
4. 使用范围
只有在失败导致退出当前上下文时才应使用guard
; 如果上下文需要继续则应该使用一个或多个if
语句。 guard
的目标是进行早期检查和返回。
5. 状态选择
如果在两个不同的状态之间进行选择,则使用if
语句而不是使用guard
语句更有意义。
最后更新于