为什么在观察者已经在主线程上运行时添加 @MainActor 可以解决我的问题?

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

我有以下粗略的代码结构:

struct MyApp: App {
    @State private var reconnecting = false

    private var showReconnectOverlay: Bool {
        return reconnecting //The actual code is more interesting of course
    }

    var body: some Scene {
        WindowGroup {
            SomeView(reconnecting: $reconnecting)
                .overlay {
                    if showReconnectOverlay { OverlayView() }
                }
        }
    }
}

struct SomeView: View {
    @Binding var reconnecting: Bool
    @State var device: MyDevice?

    var body: some View {
        AnotherView()
            .onChange(of: device?.connectionState) {
                reconnecting = device?.connectionState == .connecting
    }
}

final class MyDevice {
    private(set) var connectionState = .disconnected

    func connect() async throws {
        connectionState = .connecting

        self.connectionTask = Task {}

        if try await self.connectionTask!.value {
            connectionState = .connected //This should remove the overlay from view
        } else {
            connectionState = .disconnected
        }        
    }
}

现在的问题是,一旦连接设备,覆盖层并不总是从视图中删除。 我可以通过用

connect()
标记
@MainActor
函数来解决此问题,但我不明白为什么这可以解决问题。

我已向所有函数添加了日志记录,它们显示

reconnecting
变量已正确设置为
false
,但
showReconnectOverlay
函数始终返回
true
。 日志记录还显示
connect()
函数在非主线程上运行(这是预期的),但
onChange()
处理程序在主线程上运行。所以看来 SwiftUI 已经发挥了一些魔力。

鉴于

onChange()
处理程序已经在主线程上运行,那么用
connect()
标记
@MainActor
函数有什么区别?

swiftui swift-concurrency
1个回答
0
投票

这里关心的不是

connect()
该不该标记
@MainActor
。你的
onChange
闭包永远不会被调用,因为
MyDevice
不是
ObservableObject
。只需用
MyDevice
标记
@Observable
@Observable final class MyDevice

© www.soinside.com 2019 - 2024. All rights reserved.