swift 5.5 新出的 Async 和 Await

362 阅读2分钟

用过 JS 的同学应该对 async await 很熟悉了。但是在 swift 中,直到 2021 年的 WWDC swift 5.5,才被苹果正式推出,今天就花一点时间来讲讲新的 async / await 这两个关键字。

在此之前,异步回调都是通过 OC 时代的 Block(闭包)形式进行的。我们来用一个例子说明,比如我们有个 API 对象,可以用来获取用户信息,和设置用户信息。

struct API {
    
    /// 获取用户信息
    /// - Parameter callback: 成功回调,返回 User 对象
    static func fetchUserInfo(callback: @escaping (User) -> Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            callback(User())
        }
    }
    
    /// 设置用户信息
    /// - Parameter callback: 成功回调,返回成功或者失败
    static func setUserInfo(callback: @escaping (Bool) -> Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            callback(true)
        }
    }
}

如果先获取用户信息,修改完成后再更新用户信息,大概代码如下:

API.fetchUserInfo { user in // 获取用户信息
    user.name = "xxx" // 更改用户信息
    // 更新用户信息
    API.setUserInfo { isSucceed in
        print(isSucceed ? "用户信息更新成功" : "用户信息更新失败")
    }
}

用闭包的方式有几个明显的问题:

  1. 如果你不清楚 API 内部实现,你并不知道 Block 会回调几次

  2. 闭包形式容易造成循环引用,导致内存泄漏

  3. 嵌套地狱,一层一层的 Block 会让代码难以维护

为了避免以上提到的这些问题,我们用 async / await 来重写 API。

struct API {
    /// 获取用户信息
    /// - Returns: 返回 User 对象
    static func fetchUserInfo() async -> User {
        try? await Task.sleep(for: .seconds(3))
        return User()
    }
    
    /// 设置用户信息
    /// - Returns: 返回成功或者失败
    static func setUserInfo() async -> Bool {
        try? await Task.sleep(for: .seconds(3))
        return true
    }
}

函数上加上 async 关键字,代表这个函数是异步的,调用异步函数时,使用 await 表示代码在等待 async 的方法返回,会暂停当前的代码执行。

改完之后的调用方式:

// 获取用户信息
let user = await API.fetchUserInfo()
// 更改用户信息
user.name = "xxx"
// 更新用户信息
let isSucceed = await API.setUserInfo()
print(isSucceed ? "用户信息更新成功" : "用户信息更新失败")

这样就完美的解决了上面提到的问题。

async 也可以加在计算属性上:

var myProperty: String {
  get async {
    ...
  }
}

print(await myProperty)

async 也可以加在函数的闭包参数上:

func myFunction(worker: (Int) async -> Int) -> Int { 
  ... 
}

myFunction {
  return await computeNumbers($0)
}

点击下方公众号卡片,关注我,每天分享一个关于 iOS 的新知识

本文同步自微信公众号 “iOS新知”,每天准时分享一个新知识,这里只是同步,想要获得更好的体验就来关注我吧!