Swift 5.8 新特性

Published on
Authors
Table of Contents

Xcode 14.3 Swift 5.8

闭包内隐式调用 self(SE-0365

class Timer {
  var eventHandler: (() -> Void)?

  func start() {
    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
      self.eventHandler?()
    }
  }
}

class ViewController {
  let timer = Timer()

  init() {
    timer.eventHandler = { [weak self] in
      guard let self else { return }
      // 如果已使用 [weak self] 捕获了 self 并且解包
      // 则无需显式调用 self
      doSomething()
    }
    timer.start()
  }

  func doSomething() {
    print("Doing something...")
  }
}

集合类型支持向下类型转换

class A {}
class A1: A {}
class A2: A {}

func downcast(arr: [A]) {
  switch arr {
  case let a1 as [A1]:
    print("arr is [A1]: \(a1)")
  case let a2 as [A2]:
    print("arr is [A2]: \(a2)")
  default:
    print("Unknown collection type")
  }
}

Swift 5.8 以前,以上的代码无法通过编译。需要这样写才可以:

if let a1 = arr as? [A1] {
  //...
}

#file 与 #filePath

#file 不再输出完整的文件路径,而是以 <module-name>/<file-name> 的格式输出。

如果需要输出完成的文件路径名,使用 #filePath

print(#file)
print(#filePath)

// MagicFile/0274-magic-file.swift
// /Users/becca/Desktop/0274-magic-file.swift

这一特性目前默认是未开启的,需要在 Xcode 工程设置的 Other Swift Flags 中添加 -enable-upcoming-feature ConciseMagicFile 以开启该特性。

此外,根据 SE-0274/Concise magic file names 的描述,#file 还有利于优化二进制文件的大小和性能。

@backDeployed(before:) 属性(SE-0376)

@backDeployed(before:) 属性允许软件新版本的功能在旧版本上使用,换言之,当前版本可以使用未来版本的新功能。

如下,在 macOS 12 中定义了 Temperature 类型的结构体,在 macOS 13 时新增了一个计算属性 degreesFahrenheit 。理论上来说,macOS 12 是无法使用这个属性的。但使用 @backDeployed 之后,macOS 12 上就可以使用这个当前版本并不存在的计算属性了。

@available(macOS 12, *)
public struct Temperature {
  public var degreesCelsius: Double

  // ...
}

extension Temperature {
  @available(macOS 12, *)
  @backDeployed(before: macOS 13)
  public var degreesFahrenheit: Double {
    return (degreesCelsius * 9 / 5) + 32
  }
}

当使用 @backDeployed 标记某个功能时,编译器会在运行时检查当前版本是否包含该功能。如果有,则直接调用。如果没有,则会拷贝一个副本以供使用。

@backDeployed 目前只能用于函数、方法、下标以及计算属性。比如下面是 iOS 16.4 新增的两个修饰器方法:

public func presentationCornerRadius(_ cornerRadius: CGFloat?) -> some View

public func presentationBackgroundInteraction(_ interaction: PresentationBackgroundInteraction) -> some View

presentationCornerRadius 是可以通过 @backDeployed 在 iOS 16.4 版本之前使用的,而另一个方法则不行,因为 PresentationBackgroundInteraction 是 iOS 16.4 才引入的新类型。

解除结果生成器中变量的使用限制(SE-0373

现在可以在结果生成器中使用计算属性、lazy 变量,使用属性包装器修饰的变量等。

struct ContentView: View {

  var body: some View {
    lazy var v1: Int = .random(in: 0...10)
    var v2: Int { v1 * v1 }
    Text("v1: \(v1)") +
    Text("v2: \(v2)")
  }
}

支持 Swift-DocC 生成关于 extensions 的文档

此前使用 Swift-DocC 生成文档时,会忽略 extensions 中的内容。从 Swift-DocC plugin 1.2 和 Swift 5.8 开始,可以添加命令行参数生成关于 extensions 部分的文档。

详情请参考:Generating Documentation for Extended Types

twitterDiscuss on Twitter