参考:linkedin/swift-style-guide 因为规范主要参照谷歌的 style guide 执行,所以有一些谷歌没提到的,linkedin 提到的就补充进来。
Code Formatting
如果是多个条件判断语句,提前用变量表示判断条件。最后组合变量组合复合条件判断,而不是在一个语句中引入复杂的条件判断:
✅
let firstCondition = x == firstReallyReallyLongPredicateFunction()
let secondCondition = y == secondReallyReallyLongPredicateFunction()
let thirdCondition = z == thirdReallyReallyLongPredicateFunction()
if firstCondition && secondCondition && thirdCondition {
// do something
}
❌
if x == firstReallyReallyLongPredicateFunction()
&& y == secondReallyReallyLongPredicateFunction()
&& z == thirdReallyReallyLongPredicateFunction() {
// do something
}
命名
不要像 OC 一样在类的前面添加命名空间前缀。
泛型和协议中的 associatedtype 使用帕斯卡命名方式,如果 associatedtype 是一个常见的类型,在后面加上 “Type” 后缀表示区分。
protocol Modelable {
associatedtype Model
}
protocol Sequence {
associatedtype IteratorType: Iterator
}
- 命名应该要描述出含义,避免歧义。
✅
class RoundAnimatingButton: UIButton { /* ... */ }
❌
class CustomButton: UIButton { /* ... */ }
- 不要使用别人不理解的缩写,或者只有一个字母的名称。
❌
class RoundAnimating: UIButton {
let aniDur: NSTimeInterval
func srtAnmating() {
let v = subviews.first
}
}
- 常量、变量的类型信息如果不明显并且会引起歧义,在名称中加入类型信息。
✅
class ConnectionTableViewCell: UITableViewCell {
let personImageView: UIImageView
let animationDuration: TimeInterval
// 名字是字符串非常明显,不需要补充类型信息
let firstName: String
// 需要让人看出是一个 Controller,至于是不是叫 ViewController 则都可以接受
let popupController: UIViewController
let popupViewController: UIViewController
// 需要显式让调用者知道属性的具体类型时,也把类型信息信息写到命名中
let popupTableViewController: UITableViewController
// 应该总是让人看出是一个类型的对象
@IBOutlet weak var submitButton: UIButton!
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var nameLabel: UILabel!
}
❌
class ConnectionTableViewCell: UITableViewCell {
// 这样会让人以为是图片,而不是图片控件
let personImage: UIImageView
// 这样会让人以为是一个字符串
let text: UILabel
// 这个名称会让人不知道应该使用什么赋值,animation 与 interval 完全不相关。
let animation: TimeInterval
// 这里是一个需要展示的文本,应该命名为 `transitionText` 或者 `transitionString`
let transition: String
// 这会让人误以为是一个 UIView 对象
let popupView: UIViewController
// 不要使用缩写,所以缩写成 VC 不好
let popupVC: UIViewController
// 显式的让外面知道这是一个 TableViewController
let popupViewController: UITableViewController
// 为了保持一致性,所有的类型都写在末尾
@IBOutlet weak var btnSubmit: UIButton!
@IBOutlet weak var buttonSubmit: UIButton!
// outlet 应该总是有类型信息在末尾,这里应该是改成 firstNameLabel
@IBOutlet weak var firstName: UILabel!
}
Coding Style
常规
- 灵活运用函数式操作 map, filter, reduce 等。
✅
let stringOfInts = [1, 2, 3].flatMap { String($0) }
// ["1", "2", "3"]
❌
var stringOfInts: [String] = []
for integer in [1, 2, 3] {
stringOfInts.append(String(integer))
}
✅
let evenNumbers = [4, 8, 15, 16, 23, 42].filter { $0 % 2 == 0 }
// [4, 8, 16, 42]
❌
var evenNumbers: [Int] = []
for integer in [4, 8, 15, 16, 23, 42] {
if integer % 2 == 0 {
evenNumbers.append(integer)
}
}
- 如果一个枚举的实参可以被推断,尽量使用缩写。
✅
imageView.imageView.setImageWithURLsetImageWithURL(url, type: .person)
❌
imageView.imageView.setImageWithURLsetImageWithURL(url, type: AsyncImageView.Type.person)
正常环境下访问实例的成员不要声明
self.
。如果一个函数没有参数,没有副作用,只返回一个值,推荐使用计算属性。
访问修饰符
- 访问修饰符写在修饰符的前面,默认不用写
internal
。
自定义操作符
Switch、Enum
Switch 中的 case 语句默认就有 break 的功能,所以不需要特别声明 break。
如果 Enum 关联类型,尽量给关联类型命名带上标签。比如:
case hunger(hungerLevel: Int)
比case hunger(Int)
好。如果有一个 case 不应该到达,可以在语句中抛出异常。
func handleDigit(_ digit: Int) throws {
switch digit {
case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:
print("Yes, \(digit) is a digit!")
default:
throw Error(message: "The given number was not a digit.")
}
}
Optional
- 如果只是判断值是不是为空,使用 != nil 判断。
✅
if someOptional != nil {
// do something
}
❌
if let _ = someOptional {
// do something
}
- 解包时推荐使用原有的名字。
✅
guard let myValue = myValue else { return }
在 Extension 中实现 Protocol 要慎重
选择在 Extension 中实现 Protocol 的方法不能被 override,选择这种方式要考虑到未来是否有被 override 的可能。
Guard
- 如果解包的值后面的逻辑需要使用,推荐使用 guard 而不是 if。
✅
guard let monkeyIsland = monkeyIsland else { return }
bookVacation(on: monkeyIsland)
bragAboutVacation(at: monkeyIsland)
❌
if let monkeyIsland = monkeyIsland {
bookVacation(on: monkeyIsland)
bragAboutVacation(at: monkeyIsland)
}
❌
if monkeyIsland == nil { return }
bookVacation(on: monkeyIsland!)
bragAboutVacation(at: monkeyIsland!)
- 如果是一个逻辑分支,应该使用 if 。
✅
if isFriendly {
print("Hello, nice to meet you!")
} else {
print("You have the manners of a beggar.")
}
❌
guard isFriendly else {
print("You have the manners of a beggar.")
return
}
print("Hello, nice to meet you!")