Swift编码风格指南

swift

最近在阅读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"

优先选择结构体,只在确实需要使用到类特有的特性或者是引用语义时才使用类

swiftstruct是值类型(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!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容