1. 命名
使用驼峰式
命名法,类
、结构体
、枚举
、协议
的首字母应该大写,而方法
、变量
名首字母则小写。
private let maximumWidgetCount = 100
class WidgetContainer {
var widgetButton: UIButton
let widgetHeightPercentage = 0.85
}
1.1 枚举
对于枚举值,应该使用首字母小写的驼峰命名法:
enum Shape {
case Rectangle
case Square
case Triangle
case Circle
}
1.2 类名前缀(Class Prefix)
Swift 类型自动为模块名设置了命名空间,所以没有必要为 Swift 的类型添加类似 KS
这样的前缀了。如果两个来自不同模块的命名冲突了了,你可以在它们前面添加模块名来避免冲突。
import SomeModule
let myClass = MyModule.UsefulClass()
1.3 泛型
泛型名应该有较好的阅读性,用首字母大写的驼峰式命名。当一个类型没有有意义的关系和角色,使用传统的 T
、U
、V
来替代。
struct Stack<Element> { ... }
func writeTo<Target: OutputStream>(inout target: Target)
func max<T: Comparable>(x: T, _ y: T) -> T
1.4 语言
使用美式英语,更符合苹果的 API 标准。
2. 代码结构
2.1 代码分块
使用// MARK: -
对代码进行分块组织,代码的组织顺序从整体上尽量符合我们的认知顺序。
2.2 无用代码
对于无用的代码,都应该被删掉。
2.3 最小引用
只import
你需要的模块。比如,如果引用Foundation
以及足够,就不要再引用UIKit
了。
3. 类和结构体
3.1 选择哪个?
结构体是值类型,类是引用类型。
按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
- 该数据结构的主要目的是用来封装少量相关简单数据值。
- 有理由预计该数据结构的实例在被赋值或传递时,封装的数据将会被拷贝而不是被引用。
- 该数据结构中储存的值类型属性,也应该被拷贝,而不是被引用。
- 该数据结构不需要去继承另一个既有类型的属性或者行为。
3.2 Self 的使用
为了保持简洁,避免使用 self 关键词,Swift 不需要使用 self 来访问对象属性和调用对象方法。
在以下情况中需要使用self
:
- 在构造器中,为了区分传入的参数和属性
- 在闭包中访问属性
class BoardLocation {
let row: Int, column: Int
init(row: Int, column: Int) {
self.row = row
self.column = column
let closure = {
println(self.row)
}
}
}
3.3 计算属性
如果一个计算属性是只读的,忽略 get 语句。只有在需要定义 set 语句的时候,才提供 get 语句。
var diameter: Double {
return radius * 2
}
3.4 Final
如果类不会被继承,那么用关键词 final
标记。
final class Box<T> {
let value: T
init(_ value: T) {
self.value = value
}
}
4. 协议遵守
当我们对一个类添加协议时,推荐使用一个单独的类扩展来实现协议的方法。这可以保持协议相关的方法聚合在一起,同时也可以简单的标识出一个协议对应类中需要实现哪些对应的方法。
推荐做法:
class MyViewcontroller: UIViewController {
// class stuff here
}
// MARK: - UITableViewDataSource
extension MyViewcontroller: UITableViewDataSource {
// table view data source methods
}
// MARK: - UIScrollViewDelegate
extension MyViewcontroller: UIScrollViewDelegate {
// scroll view delegate methods
}
不推荐做法:
class MyViewcontroller: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// all methods
}
5. 函数声明
保证短的函数定义在同一行中,并且包含左大括号:
func reticulateSplines(spline: [Double]) -> Bool {
// reticulate code goes here
}
在一个长的函数定义时,在适当的地方进行换行,同时在下一行中添加一个额外的缩进:
func reticulateSplines(spline: [Double], adjustmentFactor: Double,
translateConstant: Int, comment: String) -> Bool {
// reticulate code goes here
}
6. 闭包表达式
详细参考:Swift 中的闭包
7. 类型
尽可能使用 Swift 原生类型。
7.1 常量
常量定义使用 let 关键字,变量定义使用 var 关键字,如果变量的值不需要改变,请尽量使用 let 关键字。
提示:一个好的技巧是,使用 let 定义任何东西,只有在编译器告诉我们值需要改变的时候才改成 var 定义。
7.2 可选类型
当一个变量或函数返回值可以为 nil 时,用 ?
将其声明为可选类型。
当确定变量在使用前被初始化,使用 !
来解包。
必要时,使用可选值链:
self.textContainer?.textLabel?.setNeedsDisplay()
对于需要将可选值解包,并多出使用的情况,使用可选值绑定:
if let textContainer = self.textContainer {
// do many things with textContainer
}
当我们命名一个可选变量和属性时,避免使用诸如 optionalString 和 maybeView 这样的命名,因为可选值的表达已经在类型定义中了。
在可选值绑定中,直接映射原始的命名比使用诸如 unwrappedView 和 actualLabel 要好。
推荐做法:
var subview: UIView?
var volume: Double?
// later on...
if let subview = subview, volume = volume {
// do something with unwrapped subview and volume
}
7.3 语法糖
推荐使用简短的类型声明。
推荐做法:
var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
不推荐做法:
var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>
8. 控制流
使用循环时,推荐用 for-in
表达式,而不是 for-condition-increment
表达式。