// In my root view aka Parent View
import SwiftUI
struct RootView: View {
@StateObject private var devices = DevicesViewModel()
var body: some View {
ScrollView {
UnitStatusCard(devicesVM: devices)
}
.onAppear() {
devices.fetchDevices()
}
}
}
// DeviceViewModel.swift - Parent View Model
import Foundation
class DevicesViewModel: ObservableObject {
@Published var models: [Device] = []
private let networkManager = NetworkManager<[Device]>()
init() {
fetchDevices()
}
public func fetchDevices() {
Task {
do {
if let unitId = UserDefaults.standard.string(forKey: kUnit) {
let models = try await networkManager.fetchData(path: "/api/test")
DispatchQueue.main.async {
self.models = models
}
}
} catch {...}
}
}
}
// UnitStatusCard.swift - Child View
struct UnitStatusCard: View {
@StateObject var unitStatusCardVM: UnitStatusCardViewModel
init(devicesVM: DevicesViewModel) {
self._unitStatusCardVM = StateObject(wrappedValue: UnitStatusCardViewModel(devicesVM: devicesVM))
}
var body: some View {
StatusView()
.onAppear() {
unitStatusCardVM.getStatusMeta()
}
}
}
// UnitStatusCardViewModel.swift - Child View Model
class UnitStatusCardViewModel: ObservableObject {
@Published var value: String = "Good"
var devicesVM: DevicesViewModel
init(devicesVM: DevicesViewModel) {
self.devicesVM = devicesVM
}
public func getStatusMeta() {
print(devicesVM.models) // value is [], WHY??
}
}
DeviceViewModel.swift
中,有Api调用,成功获取结果,没有错误。
然而,当我将结果传递给我的子视图模型(UnitStatusCardViewModel
)时,即使根据 ProxyMan 正确获取了该值,该值也是空的。
public func getStatusMeta() {
print(devicesVM.models) // value is [], WHY??
}
这是为什么以及如何解决?
我认为有几个因素可能导致这个结果。
fetchDevices
方法正在内部执行异步操作(虽然没有标记为异步,但它执行任务并且似乎执行某种网络调用。根据您检查模型的时间,在获取之前打印值(例如getStatusMeta
在 onAppear
上被调用,可能是在获取完成其内部执行之前。
我建议不要在 init 方法中运行
fetchDevices
,它无论如何都会在 RootView 的 onAppear 中调用,这意味着它会被调用两次,而且最终的操作会导致在创建对象时发生 ui 更改在附加到 Swift UI 视图之前或同时,可能会导致 ui 线程方面出现不良结果(那些臭名昭著的紫色/紫色警告可能会出现在 Xcode 中)开发期间)
还有一件事:为了遵守严格的并发检查,强烈建议不要像您那样使用老式的 DispatchAsync
DispatchQueue.main.async {
self.models = models
}
而是改变它
await MainActor.run {
self.models = … // make sure Device is Sendable or marked as @unchecked Sendable
}
甚至标记 作为 @MainActor 的视图模型可能是一种替代方案,因此 DeviceViewModel 属性上的任何更改都将被隔离并在主线程上本质上执行