【问题标题】:SwiftUI - Refresh view on model updated in view model arraySwiftUI - 在视图模型数组中更新模型的刷新视图
【发布时间】:2021-06-01 21:02:54
【问题描述】:

要问的问题很简单,但我可能忘记了代码中的某些内容。
让我们用一张图片更好地解释一下:

在选择/取消选择项目时,我基本上需要更新“COUNT”和“PRICE”。


我有这样的代码结构:

型号

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

    var serviceName: String
    var price: Double
    
    init(serviceName: String, price: Double) {
        self.serviceName = serviceName
        self.price = price
    }

    @Published var selected: Bool = false
}

视图模型

class ServiceSelectorViewModel: ObservableObject {
    @Published var services = [ServiceSelectorModel]()

    init() {
        self.services = [
            ServiceSelectorModel(serviceName: "SERVICE 1", price: 1.80),
            ServiceSelectorModel(serviceName: "SERVICE 2", price: 10.22),
            ServiceSelectorModel(serviceName: "SERVICE 3", price: 2.55)
        ]
    }
}

切换视图

struct ServiceToggleView: View {
    @ObservedObject var model: ServiceSelectorModel
    
    var body: some View {
        VStack(alignment: .center) {
            HStack {
                Text(model.serviceName)
                
                Toggle(isOn: $model.selected) {
                    Text(String(format: "€ +%.2f", model.price))
                        .frame(maxWidth: .infinity, alignment: .trailing)
                }
            }
            .background(model.selected ? Color.yellow : Color.clear)
        }
    }
}

ServiceSelectorView

struct ServiceSelectorView: View {

    @ObservedObject var serviceSelectorVM = ServiceSelectorViewModel()

    var body: some View {
        VStack {
            VStack(alignment: .leading) {
                ForEach (serviceSelectorVM.services, id: \.id) { service in
                    ServiceToggleView(model: service)
                }
            }

            let price = serviceSelectorVM.services.filter{ $0.selected }.map{ $0.price }.reduce(0, +)

            Text("SELECTED: \(serviceSelectorVM.services.filter{ $0.selected }.count)")
            Text(String(format: "TOTAL PRICE: €%.2f", price))    
        }
    }
}

在这段代码中,我可以更新模型的selected 状态,但包含所有模型的视图模型应该刷新PRICE 不更新
好像数组中的模型没有变化。

我忘记了什么?

【问题讨论】:

    标签: ios swift mvvm swiftui observable


    【解决方案1】:

    可能最简单的方法是将模型设为值类型,然后更改其属性,持有它的视图模型将被更新。并更新视图以使用绑定到这些值

    struct ServiceSelectorModel: Identifiable {
        var id = UUID()
    
        var serviceName: String
        var price: Double
        
        init(serviceName: String, price: Double) {
            self.serviceName = serviceName
            self.price = price
        }
    
        var selected: Bool = false
    }
    
    struct ServiceToggleView: View {
        @Binding var model: ServiceSelectorModel
    ...
    }
    
    ...
    
    ForEach (serviceSelectorVM.services.indices, id: \.self) { i in
        ServiceToggleView(model: $serviceSelectorVM.services[i])
    }
    
    

    注意:内联编写,未经测试,可能需要修复一些错字

    【讨论】:

    • 别担心错字,我只需要关于如何修复的建议,而不是复制/粘贴:)
    【解决方案2】:

    如果您仔细观察,您已经创建了两个不同的单一事实来源。这就是父母没有更新的原因,因为它没有链接到孩子。

    一种方法是将ServiceSelectorModel 创建为结构,并在子视图中将services 数组作为@Binding 传递。下面是工作示例。

    ViewModel-:

    struct ServiceSelectorModel {
        
        var id = UUID().uuidString
        var serviceName: String
        var price: Double
        var isSelected:Bool = false
        
        init(serviceName: String, price: Double) {
            self.serviceName = serviceName
            self.price = price
        }
        
    }
    
    class ServiceSelectorViewModel: ObservableObject,Identifiable {
        
        @Published var services = [ServiceSelectorModel]()
        
        var id = UUID().uuidString
        init() {
            self.services = [
                ServiceSelectorModel(serviceName: "SERVICE 1", price: 1.80),
                ServiceSelectorModel(serviceName: "SERVICE 2", price: 10.22),
                ServiceSelectorModel(serviceName: "SERVICE 3", price: 2.55)
            ]
        }
    }
    

    观看次数-:

    struct ServiceToggleView: View {
        @Binding var model: [ServiceSelectorModel]
        
        var body: some View {
            VStack(alignment: .center) {
                ForEach(0..<model.count) { index in
                    HStack{
                        Text(model[index].serviceName)
                        Toggle(isOn: $model[index].isSelected) {
                            Text(String(format: "€ +%.2f", model[index].price))
                                .frame(maxWidth: .infinity, alignment: .trailing)
                        }
                    }.background(model[index].isSelected ? Color.yellow : Color.clear)
                }
                
            }
        }
    }
    
    struct ServiceSelectorView: View {
        
        @ObservedObject var serviceSelectorVM = ServiceSelectorViewModel()
        
        var body: some View {
            VStack {
                VStack(alignment: .leading) {
                    ServiceToggleView(model: $serviceSelectorVM.services)
                }
                
                let price = serviceSelectorVM.services.filter{ $0.isSelected }.map{ $0.price }.reduce(0, +)
                
                Text("SELECTED: \(serviceSelectorVM.services.filter{ $0.isSelected }.count)")
                Text(String(format: "TOTAL PRICE: €%.2f", price))
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多