最近在阅读swift进阶这本书,其中的风格指南,我每次打开书要读的时候,我都会先看一遍这个指南,因为觉得真的很好.这里贴在简书上,和大家分享一下,有些指南后面我会加上示例代码:
对于命名,在使用时能清晰表意是最重要。因为 API 被使用的次数要远远多于被声明的次数,所以我们应当从使用者的角度来考虑它们的名字。尽快熟悉 Swift API 设计准则,并且在你自己的代码中坚持使用这些准则
// 尽量让命名语义化,而且swift不需要前缀,因为有命名空间
// GOOD
extension List {
public mutating func remove(at position: Index) -> Element
}
employees.remove(at: x)
// 反例
// BAD
extension List {
public mutating func removeAt(position: Index) -> Element
}
employees.remove(x)
简洁经常有助于代码清晰,但是简洁本身不应该独自成为我们编码的目标
务必为函数添加文档注释 — 特别是泛型函数
// 官方的API里面map函数的注释文档,记住如果你想让你的注释
// 像官方文档一样按住option单击左键就能看到,请使用 ///
// GOOD
/// Returns an array containing the results of mapping the given closure
/// over the sequence's elements.
///
/// In this example, `map` is used first to convert the names in the array
/// to lowercase strings and then to count their characters.
///
/// let cast = ["Vivien", "Marlon", "Kim", "Karl"]
/// let lowercaseNames = cast.map { $0.lowercaseString }
/// // 'lowercaseNames' == ["vivien", "marlon", "kim", "karl"]
/// let letterCounts = cast.map { $0.characters.count }
/// // 'letterCounts' == [6, 6, 3, 4]
///
/// - Parameter transform: A mapping closure. `transform` accepts an
/// element of this sequence as its parameter and returns a transformed
/// value of the same or of a different type.
/// - Returns: An array containing the transformed elements of this
/// sequence.
public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
// 反例,下面这种注释是很多人会范的错
// 更值得提示的是,请多使用MARK来给业务逻辑分段
// BAD
// map函数
public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
类型使用大写字母开头,函数、变量和枚举成员使用小写字母开头,两者都使用驼峰式命名法
// Class使用大写字母开头就不用多说了.
// 这里需要注意的是,在swift中,enum使用小写字母开头
// 这个跟OC有很大区别
// GOOD
enum RequestPath {
case index
case discover
}
// BAD
enum RequestPath {
case Index
case Discover
}
使用类型推断。省略掉显而易见的类型会有助于提高可读性
// 有人觉得使用类型推断会使得执行效率下降
// 笔者可以负责任的告诉你,完全不会,因为类型推断是编译器完成的
// GOOD
let str: String = "ABC"
// BAD
let str = "ABC"
优先选择结构体,只在确实需要使用到类特有的特性或者是引用语义时才使用类
在swift
中struct
是值类型(value type),而类是引用类型(reference type),值类型在传递的过程中是会被拷贝的,所以无副作用
除非你的设计就是希望某个类被继承使用,否则都应该将它们标记为 final
在swift
中被标记final
关键字的类,都是不允许继承的,如果是方法被标记了final
,则是不允许重写
除非一个闭包后面立即跟随有左括号,否则都应该使用尾随闭包 (trailing closure) 的语法
// GOOD
UIView.animate(withDuration: 0.3) {
}
// BAD
UIView.animate(withDuration: 0.3, animations: {
})
使用 guard 来提早退出方法
// guard可以使得条件不成立的时候执行else里面的代码
// 如果成立则继续执行下面的代码
// GOOD
guard webView.isKind(of: WKWebView.self) else {
return
}
// 执行业务代码
// BAD
if webView.isKind(of: WKWebView.self) {
// 执行业务代码
} else {
}
避免对可选值进行强制解包和隐式强制解包。它们偶尔有用,但是经常需要使用它们的话往往意味着有其他不妥的地方
这里没啥可说的,谁用谁知道,结果就是crash
,所以建议使用optional chains
self.textContainer?.textLabel?.setNeedsDisplay() // 保平安
不要写重复的代码。如果你发现你写了好几次类似的代码片段的话,试着将它们提取到一个函数里,并且考虑将这个函数转化为协议扩展的可能性
试着去使用 map 和 reduce,但这不是强制的。当合适的时候,使用 for 循环也无可厚非。高阶函数的意义是让代码可读性更高。但是如果使用 reduce 的场景难以理解的话,强行使用往往事与愿违,这种时候简单的 for 循环可能会更清晰
// map
numbers.map { $0 * 2 }
// for
for i in numbers {
i * 2
}
试着去使用不可变值:除非你需要改变某个值,否则都应该使用 let 来声明变量。不过如果能让代码更加清晰高效的话,也可以选择使用可变的版本。用函数将可变的部分封装起来,可以把它带来的副作用进行隔离
除非你确实需要,否则不要使用 self.。在闭包表达式中,使用 self 是一个清晰的信号,表明闭包将会捕获 self
// 有些开发者是从Objective - C转过来的,非常喜欢使用self
// 其实在swift中完全没有必要
// 但是在闭包中使用self是规定
anotherNum.map { num in
self.numbers.append(num)
}
尽可能地对现有的类型和协议进行扩展,而不是写一些全局函数。这有助于提高可读性,让别人更容易发现你的代码
// 多用extension
// 在开发中经常遇到这样的问题
// 如果把代理方法直接放在当前类里面会使得代码臃肿不堪
// 通过extension可以使得两者分离开
// 如果你愿意,你甚至可以写在两个文件里面都没有关系
// 比如代理方法,完全可以通过extension的方式使用
// 这样是得代码的调理性更加清晰
extension WebViewController: WKUIDelegate, WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.title = webView.title!
}
}
生命不息,折腾不止...
I'm not a real coder, but i love it so much!