我正在编写一个可取消的异步函数,其中有许多早期返回的操作,如果任务被取消。当任务成功完成或被取消时,我需要执行一些后处理撤销工作。为了实现这一点,我尝试将此逻辑放在 defer 块中,但是出现了奇怪的错误消息:
主actor隔离属性“ isPerformingAsyncWork”无法从主actor中进行突变
这是否不是直接矛盾,说明该属性只能在主actor上修改,并且您不能从主actor中对其进行突变?如何解决此问题或以其他方式执行一些代码以在任务完成/被取消时结束?
以下是演示问题的示例代码:
class ViewController: UIViewController {
var isPerformingAsyncWork = false
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
performAsyncWork()
}
func performAsyncWork() {
guard !isPerformingAsyncWork else { return }
let alert = UIAlertController(title: "Working on it…", message: nil, preferredStyle: .alert)
let task = Task {
defer {
//called upon task completion or cancelation
//FIXME: Main actor-isolated property 'isPerformingAsyncWork' can not be mutated from the main actor
isPerformingAsyncWork = false
}
isPerformingAsyncWork = true
let url = URL(string: "https://hws.dev/user-favorites.json")!
let (data, _) = try await URLSession.shared.data(from: url)
guard !Task.isCancelled else { return }
let values = try JSONDecoder().decode([Int].self, from: data)
guard !Task.isCancelled else { return }
//more async work here, more isCancelled checks, etc...
alert.presentingViewController?.dismiss(animated: true)
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { action in
task.cancel()
})
present(alert, animated: true)
}
}