有几种基本模式:
等待优先任务.
actor AdManager {
var inProgressTask: Task<Void, Error>? // if you don’t `try` anything inside the `Task {…}`, this property would be `Task<Void, Never>?`
func nextAdWithWait() async throws {
if let inProgressTask {
try await inProgressTask.value
return
}
let task = Task {
defer { inProgressTask = nil }
try await fetchAndPresentAd()
}
inProgressTask = task
// note, because this is unstructured concurrency, we want to manually handle cancelation
try await withTaskCancellationHandler {
try await task.value
} onCancel: {
task.cancel()
}
}
}
取消上一个任务并启动一个新任务.
func nextAdWithCancelPrevious() async throws {
inProgressTask?.cancel()
let task = Task {
defer { inProgressTask = nil }
try await fetchAndPresentAd()
}
inProgressTask = task
try await withTaskCancellationHandler {
try await task.value
} onCancel: {
task.cancel()
}
}
在展示了几个基本模式之后,您可能希望获取广告并在UI中呈现它们,因此您希望将获取与UI中的呈现分离.
人们可能会从某个"广告管理器"生成一个广告的异步序列,并在获取广告时产生价值.因此,用户界面可以启动"定期获取广告",然后在广告进入时对其进行处理.
actor AdManager {
/// Generate sequence of ads
func ads(durationBetweenAds: Duration = .seconds(60)) -> AsyncStream<Ad> {
AsyncStream { continuation in
let task = Task {
defer { continuation.finish() }
while !Task.isCancelled {
if let ad = await nextAd() {
continuation.yield(ad)
try? await Task.sleep(for: durationBetweenAds)
} else {
try? await Task.sleep(for: .seconds(10)) // in case ad server is down or broken, don't flood it with requests (but, at the same time, maybe not wait a full minute before you try again)
}
}
}
continuation.onTermination = { _ in
task.cancel()
}
}
}
func nextAd() async -> AdManager.Ad? {…}
}
extension AdManager {
/// model structure for a given ad … perhaps your ad platform already has a model object for this
struct Ad {…}
}
然后,用户界面可以监控该异步序列.例如,在UIKit中:
class ViewController: UIViewController {
private var adsTask: Task<Void, Never>?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
adsTask = Task { await showAds() }
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
adsTask?.cancel()
}
func showAds() async {
let adManager = await AdManager()
let ads = await adManager.ads()
for await ad in ads {
await showAdInUI(ad)
}
}
func showAdInUI(_ ad: AdManager.Ad) async {…}
}
在SwiftUI中,您不需要这种非 struct 化并发.只需直接await
在.task
视图修改器中的showAds
函数,它将在视图出现时启动它,并在视图消失时自动取消它.但是,在UIKit中,我们需要手动处理取消,如上所述.
现在,你还没有分享你的广告框架,所以上面的许多细节可能会有所不同.但不要迷失在细节中.SWIFT并发的基本思想是,您可能想要一个异步的广告序列,然后让UI迭代该序列,并在它们进入时呈现它们.这是使用异步事件序列的自然SWIFT并发模式.