Swift 5.5
中引入了并发模型,标志着异步编程变得更加简便和安全。async
和 await
关键字提供了一种干净且结构化的方式来处理异步代码。本文将深入探讨 Swift语言
的 async
和 await
的高级用法,面向希望利用这些特性开发复杂应用的高级开发人员。
关于Async
和 Await
异步 async
关键字表明函数或方法以异步方式执行其工作,而 await
用于暂停执行,直到异步操作完成。这种模式取代了旧的基于回调的方法,使异步代码看起来像同步代码一样,从而提高了可读性和可维护性。
基础示例
我们来看一个从 URL
获取数据的基础示例:
// codeun.com
import Foundation
func fetchData(from url: String) async throws -> Data {
guard let url = URL(string: url) else {
throw URLError(.badURL)
}
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
Task {
do {
// mock url
let data = try await fetchData(from: "https://www.codeun.com/")
print("Data fetched: \(data)")
} catch {
print("Failed to fetch data: \(error)")
}
}
这个示例是演示使用 fetchData
从 URL 获取数据的异步函数。关键字 await
会暂停执行,直到数据获取完毕。
进阶使用场景
下面例举几个通过 async
和 await
来更好处理的场景:
并发数据获取
假如你刚好需要同时从多个 URL
获取数据并同时处理,可以尝试使用 async let
来实现:
// codeun.com
import Foundation
func fetchMultipleData() async {
async let apiData1 = fetchData(from: "https://www.codeun.com/api01")
async let apiData2 = fetchData(from: "https://www.codeun.com/api02")
async let apiData3 = fetchData(from: "https://www.codeun.com/api03")
do {
let results = try await (apiData1, apiData2, apiData3)
print("Fetched data is: \(results)")
} catch {
print("Error fetching data is: \(error)")
}
}
Task {
await fetchMultipleData()
}
这样就可以使用 async let
来并发启动多个异步任务, await
关键字会等待所有任务完成后将再一起处理。
处理超时和取消
Swift
语言带来的结构化并发模型可以简单的处理这些场景。
// codeun.com
import Foundation
func fetchData(from url: String) async throws -> Data {
let url = URL(string: url)!
let (data, _) = try await URLSession.shared.data(from: url)
// 检查是否取消
try Task.checkCancellation()
return data
}
func fetchDataWithTimeout(from url: String) async throws -> Data {
let task = Task {
try await fetchData(from: url)
}
let timeoutTask = Task {
try await Task.sleep(nanoseconds: 5000000000)
task.cancel()
}
do {
return try await task.value
} catch {
timeoutTask.cancel()
throw error
}
}
Task {
do {
let data = try await fetchDataWithTimeout(from: "https://www.codeun.com/api01")
print("Data fetched is: \(data)")
} catch {
print("Operation timed out or was cancelled is: \(error)")
}
}
示例演示当一个任务超时导致任务未完成则会取消任务。
任务组 Task Groups
任务组可以用来创建和管理任务集合,管理并发,下面这个示例演示使用 Task Groups
任务组来同时从多个 URL
抓取数据,withThrowingTaskGroup
修饰符在任务组内创建任务并等待所有任务完成。
// codeun.com
import Foundation
func fetchMultipleDataWithGroup(urls: [String]) async throws -> [Data] {
return try await withThrowingTaskGroup(of: Data.self) { group in
for url in urls {
group.addTask {
try await fetchData(from: url)
}
}
var results: [Data] = []
for try await result in group {
results.append(result)
}
return results
}
}
Task {
do {
let urls = ["https://www.codeunn.com/api01", "https://www.codeunn.com/api02", "https://www.codeunn.com/api03"]
let data = try await fetchMultipleDataWithGroup(urls: urls)
print("Fetched data is: \(data)")
} catch {
print("Error fetching data is: \(error)")
}
}
依赖关系管理
使用 async
和 await
用来处理多个数据请求依赖,解决数据执行依赖其他结果的场景
// codeun.com
import Foundation
func fetchAndProcessData() async throws -> String {
async let data1 = fetchData(from: "https://www.codeun.com/api01")
async let data2 = fetchData(from: "https://www.codeun.com/api02")
let result1 = try await data1
let result2 = try await data2
// Process the data
let processedData = "Processed is: \(result1) and \(result2)"
return processedData
}
Task {
do {
let result = try await fetchAndProcessData()
print("Result: \(result)")
} catch {
print("Error: \(error)")
}
}
检查网络连接
在每次发起网络请求之前,都需要检查互联网连接,集成网络状态检查功能可以使用 async
和 await
异步函数完成
// codeun.com
import Foundation
import SystemConfiguration
class Reachability {
static func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) { zeroSockAddress in
SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
}
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection)
}
}
func fetchDataIfConnected(from url: String) async throws -> Data {
guard Reachability.isConnectedToNetwork() else {
throw URLError(.notConnectedToInternet)
}
return try await fetchData(from: url)
}
Task {
do {
let data = try await fetchDataIfConnected(from: "https://www.codeun.com/api")
print("Data fetched is: \(data)")
} catch {
print("Failed to fetch data is: \(error)")
}
}
本文自 https://www.codeun.com 发布,相应代码均自主编写并严格审阅和测试,完整代码中包含丰富的学习笔记和使用方式、实用技巧。
· 如若转载,请注明出处:https://www.codeun.com/archives/1463.html ·