在哪里等待以避免竞争条件并且不阻塞主线程?

问题描述 投票:0回答:0

我最近开始使用

async
/
await
(在现有的非 Swift-UI 代码库中)。 我无法得到答案的两件事(既不是通过阅读也不是通过实验)是它是否错误

await
@MainActor

上的东西

访问任务/其他 Actor 中的属性

根据我的经验,从不同的线程访问属性会导致竞争条件,不应该这样做,并且在主线程上执行阻塞操作会阻塞 UI,不应该这样做。

然而,我看到很多代码就像我在下面的(完全可运行的)示例中试图隔离的代码。

所以在

loadStuff1
中,我们可能会或可能不会在主线程上(取决于谁的电话)。它访问两个属性,
stuffLoader
param
,它们可能是从主线程读取/写入的。如我所料,这会导致比赛条件吗?你的专业人士做什么呢?

loadStuff2
中,我们肯定在主线程上。在这里等待东西安全吗?如果是,那么我想这是要走的路,但我还没有看到任何关于 await not 阻塞主线程的声明。

loadStuff3
中,我们启动了一个任务,据我所知,它会将我们的执行转移到另一个线程,该线程永远不会成为主线程。就像
loadStuff1
一样,我希望这会产生竞争条件。

import PlaygroundSupport
import UIKit

struct Stuff { }

enum Param {
    case a
    case b
}

class VM {
    private let stuffLoader = StuffLoader()
    var param: Param = .a

    func loadStuff1() async -> Stuff {
        // Is on the Main thread if the calling Thread is the Main Thread.
        await stuffLoader.load(param: param)
    }

    @MainActor func loadStuff2() async -> Stuff {
        // Is always on the Main thread.
        await stuffLoader.load(param: param)
    }

    func loadStuff3(completion: @escaping (Stuff) -> Void) {
        Task {
            // Is never on the Main thread.
            let stuff = await stuffLoader.load(param: param)
            completion(stuff)
        }
    }
}

class StuffLoader {
    func load(param: Param) async -> Stuff {
        // Here, a network call occurs and returns in 1 second.
        Stuff()
    }
}

class VC: UIViewController {
    let vm: VM

    init(vm: VM) {
        self.vm = vm
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        Task {
            let stuff = await vm.loadStuff2()
            print("Stuff 2 loaded.")
        }
    }

    func onSomethingHappened() {
        Task {
            let stuff = await vm.loadStuff1()
            print("Stuff 1 loaded.")
        }
    }

    func onSomethingElseHappened() {
        vm.loadStuff3 { stuff in
            print("Stuff 3 loaded.")
        }
    }
}

let vm = VM()
PlaygroundPage.current.liveView = VC(vm: vm)
ios swift async-await race-condition
© www.soinside.com 2019 - 2024. All rights reserved.