我有以下粗略的代码结构:
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
函数有什么区别?
这里关心的不是
connect()
该不该标记@MainActor
。你的 onChange
闭包永远不会被调用,因为 MyDevice
不是 ObservableObject
。只需用 MyDevice
标记 @Observable
:@Observable final class MyDevice