任务中的延迟块会导致“主要参与者隔离的属性“someProperty”无法从主要参与者进行突变”

Jor*_*n H 14 ios async-await swift

我正在编写一个可取消的异步函数,如果任务被取消,它会做很多工作,并散布许多早期返回。当任务成功运行完成或被取消时,我需要执行一些后处理拆卸工作。为了实现这一点,我尝试将此逻辑放入一个defer块中,但这揭示了一个奇怪的错误消息:

\n
\n

主要参与者隔离属性“isPerformingAsyncWork”无法从主要参与者进行变异

\n
\n

这不是直接矛盾吗,说这个属性只能在主角身上修改,而你不能从主角身上变异它?当任务完成/取消时,您如何解决这个问题或以其他方式执行一些代码?

\n

下面是一些示例代码来演示该问题:

\n
class ViewController: UIViewController {\n    \n    var isPerformingAsyncWork = false\n\n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n        \n        performAsyncWork()\n    }\n    \n    func performAsyncWork() {\n        guard !isPerformingAsyncWork else { return }\n        \n        let alert = UIAlertController(title: "Working on it\xe2\x80\xa6", message: nil, preferredStyle: .alert)\n        \n        let task = Task {\n            defer {\n                //called upon task completion or cancelation\n                \n                //FIXME: Main actor-isolated property 'isPerformingAsyncWork' can not be mutated from the main actor\n                isPerformingAsyncWork = false\n            }\n            \n            isPerformingAsyncWork = true\n            \n            let url = URL(string: "https://hws.dev/user-favorites.json")!\n            let (data, _) = try await URLSession.shared.data(from: url)\n            \n            guard !Task.isCancelled else { return }\n            \n            let values = try JSONDecoder().decode([Int].self, from: data)\n            \n            guard !Task.isCancelled else { return }\n            \n            //more async work here, more isCancelled checks, etc...\n\n            alert.presentingViewController?.dismiss(animated: true)\n        }\n        \n        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { action in\n            task.cancel()\n        })\n        present(alert, animated: true)\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

vad*_*ian 14

您可以生成另一个显式分派给的任务MainActor

let task = Task {
    defer {
        //called upon task completion or cancelation
        Task { @MainActor in
            isPerformingAsyncWork = false
        }
    }
...
Run Code Online (Sandbox Code Playgroud)