SwiftUI视图未随Published对象中Cat属性更新刷新,求解决方案
解决SwiftUI中类实例属性变更不触发视图刷新的问题
问题原因
你遇到的情况确实和Cat是类有关:@Published只会监听数组本身的引用变化(比如添加/删除元素、替换整个数组),而修改数组中类实例的属性时,数组的引用并没有改变,所以@Published不会发送刷新通知,cats的didSet也不会触发。
解决方案
方案1:让Cat遵循ObservableObject
把Cat改成可观察对象,用@Published标记需要监听的属性,这样每个Cat实例的属性变化都会被独立监听。
修改Cat类:
class Cat: BaseMapperModel, Identifiable, Hashable, ObservableObject { static func == (lhs: Cat, rhs: Cat) -> Bool { return ObjectIdentifier(lhs) == ObjectIdentifier(rhs) } var id = UUID() var title: String = "" @Published var quantity: Int = 0 // 标记需要监听的属性 func hash(into hasher: inout Hasher) { hasher.combine(id) } override func mapping(map: Map) { title <- map["title"] quantity <- map["qty"] } }
在视图中遍历数组时,用@ObservedObject包裹每个Cat实例:
ForEach(viewModel.cats) { cat in @ObservedObject var observedCat = cat VStack { Text(observedCat.title) Text("数量:\(observedCat.quantity)") Button("+1") { observedCat.quantity += 1 } } }
方案2:替换数组中的元素
不修改Cat类,而是在更新属性时创建一个新的Cat实例,替换数组中原位置的元素,强制触发@Published的变更通知。
修改ViewModel中的updateCatQuantity方法:
func updateCatQuantity(_ cat: Cat, qty: Int) { guard let index = cats.firstIndex(of: cat) else { return } // 创建新实例并修改属性 var updatedCat = cat updatedCat.quantity = qty // 替换原元素,触发数组变更 cats[index] = updatedCat }
方案3:手动发送变更通知
如果不想修改Cat类或数组结构,可以在修改属性后手动调用ViewModel的objectWillChange.send(),强制通知SwiftUI刷新视图。
修改ViewModel的方法:
// 确保ViewModel已经遵循ObservableObject class YourViewModel: ObservableObject { @Published var cats: [Cat] = [] func updateCatQuantity(_ cat: Cat, qty: Int) { guard let index = cats.firstIndex(of: cat) else { return } cats[index].quantity = qty // 手动发送变更通知 objectWillChange.send() } }
方案选择建议
- 若
Cat的多个属性都需要触发视图刷新,优先选方案1,实现更优雅。 - 若无法修改
Cat类的代码,选方案2或方案3,其中方案2更符合Swift值类型的变更逻辑,方案3适合临时快速解决问题。
内容的提问来源于stack exchange,提问作者soleil
相关产品推荐
相关产品推荐

