当已发布对象更改时,SwiftUI 视图不会刷新

sol*_*eil 2 swift objectmapper swiftui property-wrapper-published

在我的视图模型中,我有这个属性和方法:

@Published var cats: [Cat] = [] //this gets populated later
Run Code Online (Sandbox Code Playgroud)

当我更新其中一只猫时:

func updateCatQuantity(_ cat:Cat, qty: Int) {
    if let index = cats(of: cat) {
        cats[index].quantity = qty
    }
}
Run Code Online (Sandbox Code Playgroud)

视图不会刷新。didSetoncats不会被调用。Cat我认为这与类而不是结构这一事实有关。它的定义如下:

class Cat: BaseMapperModel, Identifiable, Hashable {
    static func == (lhs: Cat, rhs: Cat) -> Bool {
       return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
    }

    var id = UUID()

    var title: String = ""
    var quantity: Int = 0

    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }

    override func mapping(map: Map) {
        title <- map["title"]
        quantity <- map["qty"]
    }
}
Run Code Online (Sandbox Code Playgroud)

当猫的数量改变时,如何让视图刷新?

lor*_*sum 7

有 2 个问题

  1. @Published仅当“值”更改时触发刷新。更改 a 中的变量class不被视为“值”更改。

切换到 astruct是“简单”的改变。

struct Cat: Identifiable, Hashable {
    var id = UUID()

    var title: String = ""
    var quantity: Int = 0
}
Run Code Online (Sandbox Code Playgroud)

但问题#2 是一个更重要的问题。通过覆盖,Hashable您将告诉 SwiftUI 仅在更改时触发View重新加载id

要在 iOS 13-16 中观察,class对象必须符合并用,或ObservableObject包裹,在您想要看到变化的每个级别适当地。@StateObject@ObservedObject@EnvironmentObject

class Cat: Identifiable, Hashable, ObservableObject {
    var id = UUID()

    @Published var title: String = ""
    @Published var quantity: Int = 0

    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
        hasher.combine(title)
        hasher.combine(quantity)
    }
    static func == (lhs: Cat, rhs: Cat) -> Bool {
        return lhs.id == rhs.id 
        && lhs.title == rhs.title
        && lhs.quantity == rhs.quantity
    }
}
Run Code Online (Sandbox Code Playgroud)

在 iOS 17+ 中,您可以适当地使用with和@Observable来代替。ObservableObject@State@Bindable

@Observable
class Cat: Identifiable{
    var id = UUID()

    var title: String = ""
    var quantity: Int = 0
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
        hasher.combine(title)
        hasher.combine(quantity)
    }
    
    static func == (lhs: Cat, rhs: Cat) -> Bool {
        return lhs.id == rhs.id
        && lhs.title == rhs.title
        && lhs.quantity == rhs.quantity
    }
}
Run Code Online (Sandbox Code Playgroud)