寫更好的 Swift 程式碼:技巧拾遺

語言: CN / TW / HK

新增字首

為了避免命名衝突,在 OC 時代,我們的做法是在方法前面新增 snp_/sd_ 類似字首,在Swift 中我們有更優雅的處理方式:

```swift struct OD { var base: Base init(_ base: Base) { self.base = base } }

protocol ODCompatible { var od: OD {get} static var od: OD.Type {get} }

extension ODCompatible { var od: OD { OD(self) } static var od: OD.Type { OD.self } }

extension String: ODCompatible {} extension OD where Base == String { // 新增方法 func test() { print("(self)::(self.base)") } }

"A".od.test() // OD(base: "A")::A ```

快速交換值

對於這個,我們很快能寫出:

swift // 普通方法: func swapMe1<T>( a: inout T, b: inout T) { let temp = a a=b b = temp }

需要引入一個臨時變數 temp,那麼可以不通過第三個桶來交換兩個數的值麼?

swift // 使用多元組: func swapMe2<T>( a: inout T, b: inout T) { (a,b) = (b,a) }

@discardableResult 可丟棄結果

Swift 是一門要求很嚴格的語言,當函式的返回值未被使用到時,編譯器就會提示相關的警告。我們可以使用@discardableResult將函式宣告為可丟棄結果,即可告知編譯器不產生警告:

```swift

func woo() -> String { return "oldbird.run" }

@discardableResult func bar() -> String { return "關注 Oldbirds 公眾號" }

woo() // WARNING: Result of call to 'woo()' is unused

// 當然也可以賦值到佔位符 _ 以避免警告 _ = woo()

bar() ```

訪問控制

訪問控制可以限定其他原始檔或模組中程式碼對你程式碼的訪問級別。你可以明確地給單個型別(類、結構體、列舉)設定訪問級別,也可以給這些型別的屬性、函式、初始化方法、基本型別、下標索引等設定訪問級別。

Swift 為程式碼中的實體提供了四種不同的訪問級別: open、public、internal、fileprivate、private。

-w417

  • openpublic級別可以讓實體被同一模組原始檔中的所有實體訪問,在模組外也可以通過匯入該模組來訪問原始檔裡的所有實體。通常情況下,你會使用openpublic級別來指定框架的外部介面。open只能作用於類和類的成員,它和public的區別主要在於 open限定的類和成員能夠在模組外能被繼承和重寫。
  • internal級別讓實體被同一模組原始檔中的任何實體訪問,但是不能被模組外的實體訪問。通常情況下,如果某個介面只在應用程式或框架內部使用,就可以將其設定為internal級別。
  • fileprivate限制實體只能在其定義的檔案內部訪問。如果功能的部分實現細節只需要在檔案內使用時,可以使用fileprivate來將其隱藏。
  • private限制實體只能在其定義的作用域,以及同一檔案內的extension訪問。如果功能的部分細節只需要在當前作用域內使用時,可以使用private來將其隱藏。
  • 除非專門指定,否則實體預設的訪問級別為internal

更多控制細節,可參考翻譯文件

在 for 迴圈中使用 where

對於簡單的迴圈,使用 where 非常富有表現力。

```swift func archiveMarkedPosts() { for post in posts where post.isMarked { archive(post) } }

func healAllies() { for player in players where player.isAllied(to: currentPlayer) { player.heal() } } ```