美文网首页
Swift 5.1 新特性

Swift 5.1 新特性

作者: plantseeds | 来源:发表于2019-12-05 09:56 被阅读0次

    翻译自:What's New in Swift 5.1?

    Getting Started

    Swift 5.1 与 Swift 5 不仅在源代码上兼容,而且由于从 Swift 5 开始 ABI 就稳定了,Swift 5 及后续版本在二进制层面也是兼容的。

    Swift 5.1 在 Swift 5 引入的 ABI稳定性之上又增加了模块稳定性。ABI 稳定保证了应用程序运行时的兼容性,而模块稳定性保证了编译时框架的兼容性。这意味着你可以在任意版本的编译器上使用一个第三方框架,而不是仅在构建它的版本的编译器上使用。

    文中每个新特性部分都包含有 Swift Evolution 提案的编号,类似这样 [SE-00001]。你可以单击每个链接的标签来查看它的更改详情。

    Note: 如果您需要重新了解 Swfit 5 的亮点,可以查看 What's New in Swift 5

    Language Improvements

    此版本对语言做了许多新改进,包括 不透明的结果类型(opaque result types)、函数构建器(function builders)、属性包装器(property wrappers) 等等。

    1. Opaque Result Types

    在 Swift 5 中,你可以使用协议作为返回类型。

    创建一个新的 Playground,通过导航栏 View -> Navigators -> Show Project Navigator,打开 Project Navigator。右击 Sources 文件夹,选择 New File 并命名为 BlogPost。使用名为 BlogPost的新协议替换该文件的内容。

    public protocol BlogPost {
      var title: String { get }
      var author: String { get }
    }
    

    右击顶层的 playground 并选择 New Playground Page。将新页面命名为 Opaque Tutorials 并粘贴如下内容:

    // 1
    struct Tutorial: BlogPost {
      let title: String
      let author: String
    }
    
    // 2
    func createBlogPost(title: String, author: String) -> BlogPost {
      guard !title.isEmpty && !author.isEmpty else {
        fatalError("No title and/or author assigned!")
      }
      return Tutorial(title: title, author: author)
    }
    
    // 3
    let swift4Tutorial = createBlogPost(title: "What's new in Swift 4.2?",
                                        author: "Cosmin Pupăză")
    let swift5Tutorial = createBlogPost(title: "What's new in Swift 5?", 
                                        author: "Cosmin Pupăză")
    

    逐步分析:

    1. 声明 Tutorialtitleauthor,因为 Tutorial 实现了 BlogPost 协议。
    2. 定义一个函数 createBlogPost(title:author:) ,检查 titleauthor 是否有效,若有效则返回 Tutorial
    3. 使用函数 createBlogPost(title:author:) 来创建 swift4Tutorialswift5Tutorial

    您可以重用 createBlogPost(title:author:) 的原型和逻辑来创建 Screencasts

    右击顶层的 playground 并选择 New Playground Page。将新页面命名为 Opaque Screencasts 并粘贴如下内容:

    struct Screencast: BlogPost {
      let title: String
      let author: String
    }
    
    func createBlogPost(title: String, author: String) -> BlogPost {
      guard !title.isEmpty && !author.isEmpty else {
        fatalError("No title and/or author assigned!")
      }
      return Screencast(title: title, author: author)
    }
    
    let swift4Screencast = createBlogPost(title: "What's new in Swift 4.2?", 
                                          author: "Josh Steele")           
    let swift5Screencast = createBlogPost(title: "What's new in Swift 5?", 
                                          author: "Josh Steele")
    

    Screencast 实现了 BlogPost 协议,所以你可以从 createBlogPost(title:author:)中返回 Screencast 并使用 createBlogPost 来创建 swift4Screencastswift5Screencast

    导航到 Sources 文件夹下的 BlogPost.swift ,使 BlogPost 文件遵守 Equatable 协议:

    public protocol BlogPost: Equatable {
      var title: String { get }
      var author: String { get }
    }
    

    此时,你会得到一个编译错误:BlogPost 只能被用作泛型约束。这是因为 Equatable 协议有一个名为 Self 的关联类型。具有关联类型的协议不能用作类型,即使他们看起来像类型。相反,它们有点像类型占位符,表示 “它可以是遵守此类型的任何类型”。

    Swift 5.1 允许你使用 opaque result types [SE-0244],来将这类协议当做常规类型。

    Opaque Tutorials 页面,添加 some 关键字到 createBlogPost 的返回类型中,表示它会返回 BlogPost 协议的具体实现。

    func createBlogPost(title: String, author: String) -> some BlogPost {
    

    类似的,在 Opaque Screencasts 页面,使用 some 关键字告诉编译器 createBlogPost 返回某种类型的 BlogPost

    func createBlogPost(title: String, author: String) -> some BlogPost {
    

    你可以从 createBlogPost 返回实现了 BlogPOst 的任何具体类型,例如 TutorialScreencast

    现在,你可以检查前面创建的 tutorailsscreencasts 是否相同。在 Opaque Tutorials 底部,粘贴如下代码来检查 swift4Tutorialswift5Tutorial 是否相等:

    let sameTutorial = swift4Tutorial == swift5Tutorial
    

    Opaque screencasts 底部,粘贴如下代码来检查 swift4Screencastswift5Screencast 是否相等:

    let sameScreencast = swift4Screencast == swift5Screencast
    

    2. Implicit Returns From Single-Expression Functions

    在 Swift 5 中,单表达式函数中如果有返回值,需要使用 return

    extension Sequence where Element == Int {
      func addEvenNumbers() -> Int {
        return reduce(0) { $1.isMultiple(of: 2) ? $0 + $1 : $0 }
      }
    
      func addOddNumbers() -> Int {
        return reduce(0) { $1.isMultiple(of: 2) ? $0 : $0 + $1 }
      }
    }
    
    let numbers = [10, 5, 2, 7, 4]
    let evenSum = numbers.addEvenNumbers()
    let oddSum = numbers.addOddNumbers()
    

    addEvenNumbers()addOddNumbers() 中使用 reduce(_:_:) 来决定 Sequence 中偶数和奇数的总和。

    Swift 5.1 可省略单表达式函数中的 return,此时它们的行为类似于单行闭包 [SE-0255]:

    extension Sequence where Element == Int {
      func addEvenNumbers() -> Int {
        reduce(0) { $1.isMultiple(of: 2) ? $0 + $1 : $0 }
      }
    
      func addOddNumbers() -> Int {
        reduce(0) { $1.isMultiple(of: 2) ? $0 : $0 + $1 }
      }
    }
    

    这样的代码更简洁,更容易遵循。

    Note: 想要了解更多关于 reduce(_:_:) 函数的知识吗,可以查看这篇教程:An Introduction to Functional Programming in Swift.

    3. Function Builders

    Swift 5.1 使用函数构建器(function builders) 来实现构建器模式 [SE-XXXX]:

    @_functionBuilder
    struct SumBuilder {
      static func buildBlock(_ numbers: Int...) -> Int {
        return numbers.reduce(0, +)
      }
    }
    

    @_functionBuilder 来标记 SumBuilder ,使 SumBuilder 成为函数构建器类型。函数构建器是特殊的函数类型,其中每个表达式(字面量、变量名、函数调用、if 语句等)都被分别处理并用于生成单个值。例如,你可以编写一个函数,其中每个表达式将表达式的结果添加到数组中,从而形成自己的数组字面量。

    Note: 在函数构建器的标记是 @_functionBuilder ,因为此提议尚未获得批准。一旦获得批准,期望标记为 @functionBuilder

    您可以通过实现 特定名称和类型签名 的不同静态函数来创建函数构建器。buildBlock(_: T...) 是其中唯一必须实现的一个函数。还有一些函数,可以处理 if 语句、可选值和其他可被视为表达式的结构。

    您可以使用 函数构造器创建的类型名,来标记 函数或者闭包:

    func getSum(@SumBuilder builder: () -> Int) -> Int {
      builder()
    }
    
    let gcd = getSum {
      8
      12
      5
    }
    

    getSum 闭包 处理被传入的每个表达式(此例中是3个数字),将处理的结果传递给构建器,并将构建器隐式返回。函数构建器和它的隐式返回特性,是 SwiftUI 简洁语法的组成部分。它们还允许您创建自己领域的特定语言。

    译者注:以下代码可能更好理解:

    // Original source code:
    @TupleBuilder
    func build() -> (Int, Int, Int) {
    1
    2
    3
    }
    
    // This code is interpreted exactly as if it were this code:
    func build() -> (Int, Int, Int) {
    let _a = 1
    let _b = 2
    let _c = 3
    return TupleBuilder.buildBlock(_a, _b, _c)
    }
    

    4. Property Wrappers

    在 Swift 5 中使用计算属性时,你可能会处理很多样板代码:

    var settings = ["swift": true, "latestVersion": true]
    
    struct Settings {
      var isSwift: Bool {
        get {
          return settings["swift"] ?? false
        }
        set {
          settings["swift"] = newValue
       }
      }
    
      var isLatestVersion: Bool {
        get {
          return settings["latestVersion"] ?? false
        }
        set {
          settings["latestVersion"] = newValue
        }
      }
    }
    
    var newSettings = Settings()
    newSettings.isSwift
    newSettings.isLatestVersion
    newSettings.isSwift = false
    newSettings.isLatestVersion = false
    

    isSwiftisLatestVersionsettings 中获取并设置给定 key 的值。在 Swift 5.1 中可通过属性包装器(Property wrappers) [SE-0258] 来消除重复代码:

    // 1
    @propertyWrapper
    struct SettingsWrapper {
      let key: String
      let defaultValue: Bool
    
      // 2
      var wrappedValue: Bool {
        get {
          settings[key] ?? defaultValue
        }
        set {
          settings[key] = newValue
        }
      }
    }
    
    // 3
    struct Settings {
      @SettingsWrapper(key: "swift", defaultValue: false) var isSwift: Bool
      @SettingsWrapper(key: "latestVersion", defaultValue: false) 
        var isLatestVersion: Bool
    }
    

    它的工作原理如下:

    1. 使用 @propertyWrapper 标记 SettingsWrapper,使它成为属性包装器类型。
    2. 使用 wrappedValue 来获取和设置 settings 中的 key
    3. 使用 @SettingsWrapper 标记 isSwiftisLatestVersion ,并实现对应的属性包装器。
    Working with computed properties the Swifty way!.png

    5. Synthesizing Default Values for Initializers in Structures

    Swift 5 默认不会在结构体中为属性设置初始化的值,所以我们需要像这样定义初始化值:

    struct Author {
      let name: String
      var tutorialCount: Int![Diffing collections like a pro in Swift 5.1!.png](https://img.haomeiwen.com/i1610911/ff96a7fe1bb157ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    
      init(name: String, tutorialCount: Int = 0) {
        self.name = name
        self.tutorialCount = tutorialCount
      }
    }
    
    let author = Author(name: "George")
    

    我们给构造初始化器提供默认参数 tutorialCount = 0。因此在创建 author 时仅传递参数 name,并且 author.tutorialCount 默认为 0。

    Swift 5.1 让我们可以直接为结构体属性设置默认值,所以我们不必再通过自定义初始化器达到此效果 [SE-0242]:

    struct Author {
      let name: String
      var tutorialCount = 0
    }
    

    代码更干净简洁了。

    6. Self for Static Members

    在 Swift 5 中,不能使用 Self 表示数据类型的静态成员,所以我们不得不使用它的类型名代替:

    struct Editor {
      static func reviewGuidelines() {
        print("Review editing guidelines.")
      }
    
      func edit() {
        Editor.reviewGuidelines()
        print("Ready for editing!")
      }
    }
    
    let editor = Editor()
    editor.edit()
    

    如上所示,Editor 命名可能会发生变化,且命名冗长,难以维护和阅读。

    在 Swift 5.1 [SE-0068] 中,你可以使用 Self 来替换实例方法中的 Editor 引用:

    struct Editor {
      static func reviewGuidelines() {
        print("Review editing guidelines.")
      }
    
      func edit() {
        Self.reviewGuidelines()
        print("Ready for editing!")
      }
    }
    

    现在,使用 Self 来调用 reviewGuidelines() 方法。

    7. Creating Uninitialized Arrays

    在 Swift 5.1 [SE-0245] 中,我们可以创建未初始化的数组了:

    // 1
    let randomSwitches = Array<String>(unsafeUninitializedCapacity: 10) {
      buffer, initializedCount in
      // 2
      for i in 0..<5 {
        buffer[i] = Bool.random() ? "on" : "off"
      }
      // 3
      initializedCount = 5
    }
    

    逐步分析:

    1. 使用 init(unsafeUninitializedCapacity:initializingWith:) 方法创建一个具有一定容量的数组 randomSwitches
    2. 遍历 randomSwitches 并使用 random() 设置每个元素的状态。
    3. 设置 randomSwitches 初始化了的元素的数量。

    8. Diffing Ordered Collections

    Swift 5.1 使我们可以区分出有序集合之间的差异 [SE-0240]:

    let operatingSystems = ["Yosemite",
                            "El Capitan",
                            "Sierra",
                            "High Sierra",
                            "Mojave",
                            "Catalina"]
    var answers = ["Mojave",
                   "High Sierra",
                   "Sierra",
                   "El Capitan",
                   "Yosemite",
                   "Mavericks"]
    

    operatingSystems 包括了从 Swift 1 到现在的所有操作系统版本,从旧到新排序。

    answers 逆序列出了它们,并增添或删减了部分元素。

    求差异集合的Api要求我们使用 Swift 5.1 及以上版本:

    #if swift(>=5.1)
      let differences = operatingSystems.difference(from: answers)
      let sameAnswers = answers.applying(differences) ?? []
      // ["Yosemite", "El Capitan", "Sierra", "High Sierra", "Mojave", "Catalina"]
    

    使用 difference(from:) 方法,从 operatingSystemsanswers 中取得它俩之间的差异 differences ,并且使用 applying() 方法将此差异应用到 answers 中,最终得到和 operatingSystems 相同元素和顺序的数组 sameAnswers

    或者,你也可以不使用 applying() 方法,而是手动实现:

      // 1
      for change in differences.inferringMoves() {
        switch change {
          // 2
          case .insert(let offset, let element, let associatedWith):
            answers.insert(element, at: offset)
            guard let associatedWith = associatedWith else {
              print("\(element) inserted at position \(offset + 1).")
              break
            }
            print("""
                  \(element) moved from position \(associatedWith + 1) to position 
                  \(offset + 1).
                  """)
          // 3
          case .remove(let offset, let element, let associatedWith):
            answers.remove(at: offset)
            guard let associatedWith = associatedWith else {
              print("\(element) removed from position \(offset + 1).")
              break
            }
            print("""
                  \(element) removed from position \(offset + 1) because it should be 
                    at position \(associatedWith + 1).
                  """)
        }
      }
    #endif
    

    逐步分析:

    1. 使用 inferringMoves() 来确定差异中的移动元素,并遍历它们。
    2. 如果 change 类型是 .insert(offset:element:associatedWith:),则向 answers 数组中位于 offset 处 添加元素 element。如果 associatedWith 值不为 nil,则将此次操作视为 answers 数组内部的元素位置移动,而不是从外部新加的元素。
    3. 如果 change 类型是 .remove(offset:element:associatedWith:),则向 answers 数组中位于 offset 处 删除元素 element。如果 associatedWith 值不为 nil,则将此次操作视为 answers 数组内部的元素位置移动,而不是将该元素从数组中删除了。
    Diffing collections like a pro in Swift 5.1!.png

    9. Static and Class Subscripts

    Swift 5.1 允许我们在类型(class / struct / enum) 中声明 staticclass subscripts [SE-0254]:

    // 1
    @dynamicMemberLookup
    class File {
      let name: String
    
      init(name: String) {
        self.name = name
      }
    
      // 2
      static subscript(key: String) -> String {
        switch key {
          case "path":
            return "custom path"
          default:
            return "default path"
        }
      }
    
      // 3
      class subscript(dynamicMember key: String) -> String {
        switch key {
          case "path":
            return "custom path"
          default:
            return "default path"
        }
      }
    }
    
    // 4
    File["path"]
    File["PATH"]
    File.path
    File.PATH
    

    逐步分析:

    1. @dynamicMemberLookup 标记 File ,以使 File 支持点语法的动态成员查找。
    2. 创建一个静态下标方法,返回默认值或自定义的值。
    3. 定义一个 class 类型的动态成员查找方法。
    4. 用相应的语法调用这两种下标。

    Note: 想要了解更多关于 Swift subscripts 的知识吗?请看这里 Custom Subscripts in Swift.

    10. Dynamic Member Lookup for Keypaths

    Swift 5.1 实现了基于 keypaths 的动态成员查找方法 [SE-0252]:

    // 1
    struct Point {
      let x, y: Int
    }
    
    // 2
    @dynamicMemberLookup
    struct Circle<T> {
      let center: T
      let radius: Int
    
      // 3
      subscript<U>(dynamicMember keyPath: KeyPath<T, U>) -> U {
        center[keyPath: keyPath]
      }
    }
    
    // 4
    let center = Point(x: 1, y: 2)
    let circle = Circle(center: center, radius: 1)
    circle.x
    circle.y
    

    逐步分析:

    1. Point 声明 xy 属性。
    2. @dynamicMemberLookup 标记 Circle ,以使 Circle 支持点语法的动态成员查找。
    3. 创建一个 使用 keypaths 的泛型下标方法,用来获取 Circlecenter 的属性。
    4. 使用动态成员查找来代替keypaths,直接在 circle 上调用 center 的属性。

    Note: 想要了解更多关于动态成员查找的知识吗?请看 Dynamic Features in Swift.

    11. Keypaths for Tuples

    在 Swift 5.1 中,我们可以为元组使用 keypaths 了:

    // 1
    struct Instrument {
      let brand: String
      let year: Int
      let details: (type: String, pitch: String)
    }
    
    // 2
    let instrument = Instrument(brand: "Roland",
                                year: 2019,
                                details: (type: "acoustic", pitch: "C"))
    let type = instrument[keyPath: \Instrument.details.type]
    let pitch = instrument[keyPath: \Instrument.details.pitch]
    

    逐步分析:

    1. Instrument 声明 brand, yeardetails 属性。
    2. 使用 keypaths,从 instrumentdetails 属性中获取 typepitch

    12. Equatable and Hashable Conformance for Weak and Unowned Properties

    Swift 5.1 为有 weakunowned 存储属性的结构体 自动合成 EquatableHashable 一致性。

    假设有如下两个类:

    class Key {
      let note: String
    
      init(note: String) {
        self.note = note
      }
    }
    
    extension Key: Hashable {
      static func == (lhs: Key, rhs: Key) -> Bool {
        lhs.note == rhs.note
      }
    
      func hash(into hasher: inout Hasher) {
        hasher.combine(note)
      }
    }
    
    class Chord {
      let note: String
    
      init(note: String) {
        self.note = note
      }
    }
    
    extension Chord: Hashable {
      static func == (lhs: Chord, rhs: Chord) -> Bool {
        lhs.note == rhs.note
      }
    
      func hash(into hasher: inout Hasher) {
        hasher.combine(note)
      }
    }
    

    KeyChord 都遵守 EquatableHashable 协议,因为它们实现了 ==(lhs:rhs:)hash(into:) 方法。

    如果你在结构体中使用这种类型,Swift 5.1 将自动为你合成 Hashable 一致性,而不需要你手动实现 ==(lhs:rhs:)hash(into:) 方法:

    struct Tune: Hashable {
      unowned let key: Key
      weak var chord: Chord?
    }
    
    let key = Key(note: "C")
    let chord = Chord(note: "C")
    let tune = Tune(key: key, chord: chord)
    let chordlessTune = Tune(key: key, chord: nil)
    let sameTune = tune == chordlessTune
    let tuneSet: Set = [tune, chordlessTune]
    let tuneDictionary = [tune: [tune.key.note, tune.chord?.note], 
                          chordlessTune: [chordlessTune.key.note, 
                          chordlessTune.chord?.note]]
    

    Tune 是遵守 EquatableHashable 协议的,因为 Tune 的属性 keychord 是遵守 EquatableHashable 的。

    因为 Tune 遵守 Hashable 协议,所以你可以比较 tunechordlessTune ,把它们加入 tuneSet 集合中,并使用它们作为 tuneDictionary 字典的keys。

    13. Ambiguous Enumeration Cases

    Swift 5.1 会为模棱两可的枚举类型生成警告⚠️。

    // 1
    enum TutorialStyle {
      case cookbook, stepByStep, none
    }
    
    // 2
    let style: TutorialStyle? = .none
    

    逐步分析:

    1. TutorialStyle 定义不同的 style。
    2. Swift 发出一个警告,因为在这儿, .none 对于编译器来说是不明确的,它可以是 Optional.none ,也可以是 TutorialStyle.none

    14. Matching Optional Enumerations Against Non-optionals

    在 Swift 5 中,对于 可选的枚举类型,我们需要使用 可选模式 来匹配 不可选的值:

    // 1
    enum TutorialStatus {
      case written, edited, published
    }
    
    // 2
    let status: TutorialStatus? = .published
    
    switch status {
      case .written?:
        print("Ready for editing!")
      case .edited?:
        print("Ready to publish!")
      case .published?:
        print("Live!")
      case .none:
        break
    }
    

    逐步分析:

    1. TutorialStatus 声明所有可能的状态。
    2. 使用可选模式匹配来匹配 status ,因为我们把它定义为了可选值。

    Swift 5.1 移除了此例中的可选模式匹配:

    switch status {
      case .written:
        print("Ready for editing!")
      case .edited:
        print("Ready to publish!")
      case .published:
        print("Live!")
      case .none:
        break
    }
    

    代码更加清晰,且容易理解了。

    Note: 想要了解更多关于模式匹配的知识吗?请看这里 Pattern Matching in Swift.

    15. New Features for Strings

    Swift 5.1 为字符串添加了一些急需的功能 [SE-0248]:

    UTF8.width("S")
    UTF8.isASCII(83)
    

    现在,你可以确定 Unicode 标量值得 UTF-8 编码宽度,并检查给定的码元是否是一个 ASCII 标量。查看提案中其他可能使用的APIs [SE-0248].

    16. Contiguous Strings

    Swift 5.1 实现了对连续字符串的重要的更改 [SE-0247]:

    var string = "Swift 5.1"
    if !string.isContiguousUTF8 {
      string.makeContiguousUTF8()
    }
    

    你可以使用 isContiguousUTF8 来检查 UTF-8 编码的字符串在内存上是否是连续的,并使用 makeContiguousUTF8() 方法来使它成为连续的字符串。去提案中查看你还可以通过连续的字符串做些什么 [SE-0247]。

    17. Converting Tuple Types

    Swift 5.1 改进了元组类型的转换:

    let temperatures: (Int, Int) = (25, 30)
    let convertedTemperatures: (Int?, Any) = temperatures
    

    现在可以把 temperatures 赋值给 convertedTemperatures,因为此例中 (Int, Int) 可以转换为 (Int?, Any)

    18. Tuples with Duplicate Labels

    在 Swift 5 中,可以用重复的标签声明元组中的元素:

    let point = (coordinate: 1, coordinate: 2)
    point.coordinate
    

    此例中,我们并不能明确的知道 point.coordinate 是返回了第一个还是第二个元素。因此 Swift 5.1 不允许元组中声明重复的标签。

    19. Overloading Functions with Any Parameters

    对于只有一个参数的重载函数,Swift 5 更倾向于调用带 Any 参数的函数 而非 带泛型参数的函数:

    func showInfo(_: Any) -> String {
      return "Any value"
    }
    
    func showInfo<T>(_: T) -> String {
      return "Generic value"
    }
    
    showInfo("Swift")
    

    在 Swift 5 中, showInfo() 将返回 "Any value"

    而在 Swift 5.1 中, showInfo() 将返回 Generic value

    20. Type Aliases for Autoclosure Parameters

    在 Swfit 5 中,不能为自动闭包参数 @autoclosure 声明别名:

    struct Closure<T> {
      func apply(closure: @autoclosure () -> T) {
        closure()
      }
    }
    

    函数 apply(closure:) 中的参数 closure 使用了自动闭包签名。

    在 Swift 5.1 中,可以在函数 apply(closure:) 中使用自动闭包类型参数的别名:

    struct Closure<T> {
      typealias ClosureType = () -> T
    
      func apply(closure:  @autoclosure ClosureType) {
        closure()
      }
    }
    

    这次,函数 apply(closure:) 的参数 closure 使用了 ClosureType 类型来声明。

    21. Returning Self From Objective-C methods

    在 Swift 5 中,如果 **class ** 中含有 @objc 的方法并返回了 Self,则该 class 必须继承于 NSObject

    class Clone: NSObject {
      @objc func clone() -> Self {
        return self
      }
    }
    

    例中 Clone 继承于 NSObject 因为 clone() 方法返回了 Self

    在 Swift 5.1 中,将不再必须继承 NSObject

    class Clone {
      @objc func clone() -> Self {
        self
      }
    }
    

    现在 Clone 不必继承任何类了。

    22. Stable ABI Libraries

    您可以在 Swift 5.1 中使用 -enable-library-evolution 来更改库类型,而不破坏它的 ABI。标记为 @frozen 的结构体和枚举不能 添加、删除 或 重新排序存储属性和方法 [SE-0260]。

    最后

    Swift 5.1 在 Swift 5 的基础上添加了许多很棒的功能。它也为 Swift语言带来了模块稳定性,并实现了 WWDC 中引入的新框架,如:SwiftUI 和 Combnine。

    您可以在 Swift 官方的 CHANGELOG 或者 Swift standard library differences 中了解到更多关于 Swift 语言的变动。

    您也可以在 Swift Evolution 中查看Swift下个版本会带来什么新特性。在这里,您可以为当前在审阅的提案提供反馈,甚至可以自己提出提案,为Swift语言舔砖加瓦!

    相关文章

      网友评论

          本文标题:Swift 5.1 新特性

          本文链接:https://www.haomeiwen.com/subject/drbrgctx.html