Swift 5.3 預發布特性搶先看

Tibor Bodecs · 2020-05-18
本文來自 知識小集 ,作者 Tibor Bodecs

image.png

作者 | Tibor Bodecs 
來源 | https://theswiftdev.com/

Swift 5.3將是一個令人興奮的新版本。這篇文章展示了最新的 Swift 特性。

從 Apple 在 3 月下旬公布 Swift 5.3 發布流程至今,5.3 分支上已經實現了許多新功能。如果你想了解一下都有什么新功能,可以使用 swiftenv 安裝最新快照來體驗一下。

Package Manager 更新

Swift Package tool 5.3 版本引入了一些非常好的功能。

資源

隨著 SE-0271 的實現,Swift Package Manager 最終可以將資源文件與代碼打包在一起。我相信這是一個非常受歡迎的新功能,因為有些庫需要嵌入資產文件,但目前為止 SPM 還無法支持。

本地化資源

SE-0278 擴展了資源支持,通過此實現,可以為 Swift 軟件包聲明本地化的資源。SE-0278 的描述解釋了提議的詳細信息,如果需要隨包一起發布本地化文件,可以看看。

二進制依賴

另一個很棒的事情是 SPM 最終將能夠使用二進制依賴項。SE-0272添加了此功能,因此如果希望提供閉源的人現在可以使用此功能。這樣可以在給定的路徑或位置設置 binaryTarget 依賴性,并且可以將二進制文件用于庫或或執行文件。

條件目標依賴

SE-0273 提供了一個很好的補充,可以使用基于給定平臺的依賴項。這意味著在為特定平臺構建產品時,可以將產品用于一個 target。

以上功能是對 SPM 的重要補充,希望 Xcode 也能從這些功能中受益,并且我們還將在即將發布的 IDE 版本中看到一些重大的新的增強功能。

語言特性

5.3 版本中引入了許多有趣的新提議。

多個尾隨閉包

SE-0279 是爭議最大的新提案之一。當我第一次看到它時,我不確定是否需要它,為什么有人會花這么大的力氣消除一些括號呢?

import UIKit

class ViewController: UIViewController {

   override func viewDidLoad() {
       super.viewDidLoad()

       // old
       UIView.animate(withDuration: 0.3, animations: {
         self.view.alpha = 0
       }, completion: { _ in
         self.view.removeFromSuperview()
       })
       // still old
       UIView.animate(withDuration: 0.3, animations: {
         self.view.alpha = 0
       }) { _ in
         self.view.removeFromSuperview()
       }

       // new
       UIView.animate(withDuration: 0.3) {
         self.view.alpha = 0
       }
       
       UIView.animate(withDuration: 0.3) {
           self.view.alpha = 0
       } completion: { _ in
           self.view.removeFromSuperview()
       }
   }
}

如你所見,這主要是一種語法糖,但是我說服自己擁有它是很好的。

為枚舉類型合成 Comparable

由于 SE-0266,Enum 類型不必顯式實現 Comparable 協議。

enum Membership: Comparable {
   case premium(Int)
   case preferred
   case general
}
([.preferred, .premium(1), .general, .premium(0)] as [Membership]).sorted()

Comparable 協議是自動合成的,就像其它類型的 Equatable 和 Hashable 一樣。當然,如果需要,您可以提供自己的實現。

枚舉的 case 實現協議

Swift 的枚舉是功能強大構建基塊,現在它們變得更好了。

protocol DecodingError {
 static var fileCorrupted: Self { get }
 static func keyNotFound(_ key: String) -> Self
}

enum JSONDecodingError: DecodingError {
 case fileCorrupted
 case keyNotFound(_ key: String)
}

SE-0280 的主要目標是解除現有限制,如果枚舉提供的 case 其命名和參數能符合協議的要求,則枚舉可以作為協議的一個實現。

基于類型的程序入口點

SE-0281為我們提供了一個新的 @main 屬性,可以使用該屬性來定義應用程序的入口點。這是一個很好的補充,不必再編寫 MyApp.main() 方法,而只需用main屬性標記 MyApp 對象。

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

   static func main() {
       print("App will launch & exit right away.")
   }
}

不推薦使用UIApplicationMain和NSApplicationMain屬性,而推薦使用@main,我敢打賭這將在下一個主要版本中發布...

多模式 Catch

SE-0276 是另一種語法糖,非常方便同時捕獲多個異常。

do {
   try performTask()
}
catch TaskError.someRecoverableError {
   recover()
}
catch TaskError.someFailure(let msg), TaskError.anotherFailure(let msg) {
   showMessage(msg)
}

這消除了在 catch 塊中使用 switch case。

Float16

SE-0277 將 Float16 添加到標準庫中。

let f16: Float16 = 3.14

泛型數學函數也即將推出...

Self 的改變

SE-0269 aka。對于那些不太愿意寫 self 的人來說,在不太可能發生引用循環時提高@escaping 閉包中隱式 self 的可用性是一個不錯的選擇。

//old
execute {
   let foo = self.doFirstThing()
   performWork(with: self.bar)
   self.doSecondThing(with: foo)
   self.cleanup()
}

//new
execute { [self] in
   let foo = doFirstThing()
   performWork(with: bar)
   doSecondThing(with: foo)
   cleanup()
}

這將允許我們僅將self寫入捕獲列表,而稍后在塊內將其忽略。

完善 didSet 語義

SE-0268 是一個底層改進,使 didSet 行為更佳,更可靠。

class Foo {
   var bar = 0 {
       didSet { print("didSet called") }
   }

   var baz = 0 {
       didSet { print(oldValue) }
   }
}

let foo = Foo()
// This will not call the getter to fetch the oldValue
foo.bar = 1
// This will call the getter to fetch the oldValue
foo.baz = 2

簡而言之,以前總是調用屬性的getter,但是從現在開始,僅當我們使用 didSet 塊中的 oldValue 參數時,才調用該方法。

在非連續元素上添加集合操作

SE-0270 添加了一個 RangeSet 類型來表示多個不連續的范圍,以及用于創建和使用范圍集的各種集合操作。

var numbers = Array(1...15)

// Find the indices of all the even numbers
let indicesOfEvens = numbers.subranges(where: { $0.isMultiple(of: 2) })

// Perform an operation with just the even numbers
let sumOfEvens = numbers[indicesOfEvens].reduce(0, +)
// sumOfEvens == 56

// You can gather the even numbers at the beginning
let rangeOfEvens = numbers.moveSubranges(indicesOfEvens, to: numbers.startIndex)
// numbers == [2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15]
// numbers[rangeOfEvens] == [2, 4, 6, 8, 10, 12, 14]

該建議還通過一些使用RangeSet類型的API方法擴展了Collection類型,如果您經常使用范圍,則應該看看。

上下文范型聲明的 where子句

如果僅引用泛型參數,則使用 SE-0267 可以實現函數并在其上施加where約束??紤]以下代碼段:

protocol P {
   func foo()
}

extension P {
   func foo() where Self: Equatable {
       print("lol")
   }
}

這在老版本上無法編譯,但是在 Swift 5.3 之后它將像魔術一樣工作。

添加可訪問未初始化存儲的字符串初始化器

SE-0263 添加了一個新的String初始化器,使您可以使用未初始化的緩沖區。

let myCocoaString = NSString("The quick brown fox jumps over the lazy dog") as CFString
var myString = String(unsafeUninitializedCapacity: CFStringGetMaximumSizeForEncoding(myCocoaString, ...)) { buffer in
   var initializedCount = 0
   CFStringGetBytes(
       myCocoaString,
       buffer,
       ...,
       &initializedCount
   )
   return initializedCount
}
// myString == "The quick brown fox jumps over the lazy dog"

通過使用這種新的init方法,您不必再擔心不安全的指針了。

Swift的未來發展

目前,在Swift的開發面板上還有6個被接受的提案,其中一個正在接受審核。Swift 5.3將包含一些社區期待已久的驚人新功能。我很高興該語言朝著正確的方向發展。

实盘配资