Swift 5.7 note

译自 Swift 5.7: Optional Binding, Closure Type Inference, Clock, Noasync

什么是Swift

Apple 的swift是一种运行在 iOS,MacOS,WatchOS,TvOS以及 linux上的编程语言。

Swift是一种可编译的跑在apple相关产品设备以及电脑的类linux系统上的语言。这些系统上的应用可以使用c,c++,ObjectiveC等语言和swift 混合开发编译运行。

我们啥时可以开始使用swift 5.7?

根据最新消息,5.7 将于xcode14 以及 iOS SDK16 开始使用。

根据最新消息,swift将有哪些新的变化?

根据介绍,最主要的让开发者们的工作变得更轻松的点有,增强和简化了最常用的开发工具比如 binding optional语法;还有一些常用的表达式语法以及常用语法。

速记:隐藏一个现有的optional变量

什么是optional变量?

optional变量在swift里可以赋予一个有效的值或对象或是一个空指针。

作为一个iOS的swift开发者,在编码时要经常使用到optional变量,它可以决定变量/容器是否可以赋值/包含 nil。

在编码时检查一个变量是否有值是跟呼吸一样频繁的事。

尽管使用起来已经够简单了,但每次都要把很长的变量名重写一遍还是比较麻烦。swift5.7 就在这方面很好地改进了相关语法。

  • 之前的swift
let colleageName : String? = "John"
if let colleageName = colleageName {
  print(colleageName)
}

有时变量名过长时,每次重写就有点繁琐,或者有时候超过了一行的字数限制。

下面的代码就显得特别冗长而且可读性较差

let colleageNameiohfahiefhaohgho : String? = "John"
let colleageNameiohfahiefhaohgho2 : String? = "Bill"
if let colleageNameiohfahiefhaohgho = colleageNameiohfahiefhaohgho,
  let colleageNameiohfahiefhaohgho2 = colleageNameiohfahiefhaohgho2
 {
  print("\(colleageNameiohfahiefhaohgho) \(colleageNameiohfahiefhaohgho2)")
}

而且这会导致变量命名趋向于简短且描述性差。

这会让其他开发者或是自己在接下来的编码中难以理解这些变量的真正意义。

let colleageNameiohfahiefhaohgho : String? = "John"
let colleageNameiohfahiefhaohgho2 : String? = "Bill"
if let name1 = colleageNameiohfahiefhaohgho,
  let name2 = colleageNameiohfahiefhaohgho2
 {
  print("\(name1) \(name2)")
}
  • 在swift5.7里 上述场景的语法被简化和改进了
let colleageName : String? = "John"
if let colleageName {
  print(colleageName)
}

而且在其他的条件控制语句里也可以使用

if let foo { ... }
if var foo { ... }
else if let foo { ... }
else if var foo { ... }
guard let foo else { ... }
guard var foo else { ... }
while let foo { ... }
while var foo { ... }
  • 使用限制 主要限制在于 不能如此使用一个对象的 optional 属性。
class Animal {
  var name : String? = "dog"
}
let ani = Animal()
if let name = ani.name { //编译正确
}
if let ani.name { //编译❌
}

闭包类型的引用

swift理解闭包的能力大大增强了,当闭包返回一个不可变的简单数据类型时,swfit能很轻松地推断出返回的具体类型。 但如果闭包语法复杂一些时,推断起来就没那么轻松了。

  • 在下面的例子里,用到了String的list
let numbers = [1,2,3]
let numberStrings = numbers.map {"\($0)"}

如果我们把闭包改得稍微复杂一点,swift会抛出一个编译错误,要求你明确指定返回的类型。

let numberString = [1,2,3].map { num in //编译❌
  let s = "1"
  return s
}
  • 在swift5.7前,我们有两种方法来解决这个错误
  1. 限定闭包的返回类型
let numberString = [1,2,3].map { num -> String in
  let s = "1"
  return s
}
  1. 设定我们需要map函数返回的数据类型
let numberString : [String] = [1,2,3].map { num  in
  let s = "1"
  return s
}
  • 但在swift5.7里,swift的推导会更加智能,能正确推导出闭包返回类型,就不会报错了。
let numberString = [1,2,3].map { num in //编译ok
  let s = "1"
  return s
}

Clock 协议 (SE-0329)

在iOS16里,新增了一个Clock协议,它声明了一套 时间和时间段的标准化接口,可以用来表达时长,也能用来做定时的延时工作。

它包含三个主要部分

  • Clocks: 作为时长的丈量方法,可用来设定延迟或是当前时间戳,它由两个内置模块组成

    • ContinuousClock: 一种用来丈量时长的Clock,它会一直不停递增,甚至在系统睡眠时也不会停。
    • SuspendingClock: 跟上面的不同之处在于 系统睡眠时它会暂停。
  • Instants: 代表一个确定的时间点

  • Durations:代表两个clock实例间相差多少时长

try await Task.sleep(until: .now +  .seconds(1), clock: .continuous)

tolerance 参数用来处理性能相关事项,Clock可以用一个设定的重新设定一个未来任务的发生时间。 如果没设置 tolerance 参数,那么会有个默认值被设置上去。

try await Task.sleep(until: .now + .seconds(1),
                     tolerance: .seconds(0.5), 
                     clock: .continuous)

也可以用clock去计算一个API的执行时间。

@available(iOS 16.0, *)
let clock = ContinuousClock()
let time = clock.measure {
    // complex work here
}
print("Took \(time.components.seconds) seconds")

禁用Async(异步)功能 (SE-0340)

新增了一种在swift里的多任务并行执行场景的保护手段。现在可以将类型或是函数标识为不支持异步调用操作。

@available 可以用来标识类型或函数的支持功能或版本,但用新增的 noasync 来标识的话。

@available(*, noasync)
    func doRiskyWork() {
        
    }

虽然我们还是可以像往常一样直接调用该函数,但如果在标明为 async 的异步方法里使用它的话,xcode会抛一个warning,表示这是不正确的调用方式。

func sssync() async {
        doRiskyWork() //Instance method 'doRiskyWork' is unavailable from asynchronous contexts; this is an error in Swift 6
    }

但只能用于直接调用标识为 noasync 函数的场景,如果嵌套多一层,xcode就不会抛warning了,但实际使用中还是可能出问题,需要注意这点。

@available(*, noasync)
    func doRiskyWork() {
        
    }
    
    func sssync() async {
        doRiskyWork() //有warning
    }
    
    func sssync1() async {
        await sssync() //无warning
    }

结论

swfit5.7 还有很多更新在这篇文章里没有列出来。比如一些功能强大的API pointer API , Swift regex, opaques result type, distributed actors, many others.

在这些更新点的支持下,提供了大量的新功能,但同时也淘汰了正在使用的一些方法。不过我坚信它们能让开发的代码质量更好,同时也让swift 变得更加可靠。