WWDC21上发布了Swift 5.5,虽然是小版本,但是特性不少……
Async/await
SE-0296提案终于为开发者带来了期待已久的 async
/await
,语法基本上和javascript中的很像。
老的方式
以前写异步函数像这样
代码语言:javascript复制func fetchWeatherHistory(completion: @escaping ([Double]) -> Void) {
// Complex networking code here; we'll just send back 100,000 random temperatures
DispatchQueue.global().async {
let results = (1...100_000).map { _ in Double.random(in: -10...30) }
completion(results)
}
}
func calculateAverageTemperature(for records: [Double], completion: @escaping (Double) -> Void) {
// Sum our array then divide by the array size
DispatchQueue.global().async {
let total = records.reduce(0, )
let average = total / Double(records.count)
completion(average)
}
}
func upload(result: Double, completion: @escaping (String) -> Void) {
// More complex networking code; we'll just send back "OK"
DispatchQueue.global().async {
completion("OK")
}
}
这样调用
代码语言:javascript复制fetchWeatherHistory { records in
calculateAverageTemperature(for: records) { average in
upload(result: average) { response in
print("Server response: (response)")
}
}
}
存在的问题是
- 回调函数很容易调用多次,或者忘记调用。
- 函数参数
@escaping (String) -> Void
看着也不直观 - “回调地狱”看起来也不美观
- 在Swift 5.0 增加了
Result
类型之前,返回错误也困难。
Swift 5.5 Async/await方式
代码语言:javascript复制func fetchWeatherHistory() async -> [Double] {
(1...100_000).map { _ in Double.random(in: -10...30) }
}
func calculateAverageTemperature(for records: [Double]) async -> Double {
let total = records.reduce(0, )
let average = total / Double(records.count)
return average
}
func upload(result: Double) async -> String {
"OK"
}
使用也更简单
代码语言:javascript复制func processWeather() async {
let records = await fetchWeatherHistory()
let average = await calculateAverageTemperature(for: records)
let response = await upload(result: average)
print("Server response: (response)")
}
Async / await 错误处理
swift 5.5 async 函数也可以像普通函数一样抛出错误 async throws
。
enum UserError: Error {
case invalidCount, dataTooLong
}
func fetchUsers(count: Int) async throws -> [String] {
if count > 3 {
// Don't attempt to fetch too many users
throw UserError.invalidCount
}
// Complex networking code here; we'll just send back up to `count` users
return Array(["Antoni", "Karamo", "Tan"].prefix(count))
}
func save(users: [String]) async throws -> String {
let savedUsers = users.joined(separator: ",")
if savedUsers.count > 32 {
throw UserError.dataTooLong
} else {
// Actual saving code would go here
return "Saved (savedUsers)!"
}
}
使用也是类似
代码语言:javascript复制func updateUsers() async {
do {
let users = try await fetchUsers(count: 3)
let result = try await save(users: users)
print(result)
} catch {
print("Oops!")
}
}