SwiftUI:如何更改 @Published 对象值。更改已发布变量的值不起作用

Azh*_*mil 1 ios swift swiftui

我正在做一个由 5 个带有单选按钮的选项组成的页面。当我们点击一​​个选项时,元素的颜色应该改变。我从 API 响应中获取这些选项。我正在使用 MVVM 模型。我附上下面的代码。

我所困扰的是,当我改变布尔值时,它没有改变!

查看型号代码

import Foundation
import Combine

class DCListViewModel: ObservableObject {
    @Published var DCList = [DCViewModel]()

    init() {
        fetchDcs()
    }

    func fetchDcs() {
        ARMServices().getAllDc { (dcArr) in
            if let dcArr = dcArr {
                for dc in dcArr{
                    self.DCList.append(DCViewModel(dc: dc, isSelected: false))
                }
            }
        }
    }
}


class DCViewModel {
    var id = UUID()
    var dcStruct: DC
    var isSelected: Bool

    init(dc: DC, isSelected: Bool) {
        self.dcStruct = dc
        self.isSelected = isSelected
    }

    var url: String {
        return self.dcStruct.url  ?? "empty URL"
    }

    var dc: String {
        return self.dcStruct.dc ?? "empty dc name"
    }
}
Run Code Online (Sandbox Code Playgroud)

查看页面代码

struct SelectTableView: View {

    var body: some View {
        NavigationView {

                VStack {
                    DCListView(dcList: self.dcListVM.DCList)
                        .padding(.horizontal)
                }
            .navigationBarTitle("Select the Data Centre")
        }
    }
}


struct DCListView: View{
    var dcList: [DCViewModel]

    init(dcList: [DCViewModel]) {
        self.dcList = dcList
    }

    var body: some View {
        ForEach(self.dcList, id: \.id) { dc in
            Button(action: {
                print("Tapped")
                dc.isSelected.toggle()
            }){
                ZStack {
                    RoundedRectangle(cornerRadius: 8)
                        .stroke(dc.isSelected ? Color.init("borderSelected"): Color.init("border"))
                        .frame(height: 56)
                        .foregroundColor(.clear)

                    HStack {
                        Text(dc.dc)
                            .font(.custom("Montserrat", size: 16))
                            .fontWeight(.medium)
                            .foregroundColor(dc.isSelected ? Color.init("borderSelected") : .white)
                            .padding()

                        Spacer()

                        ZStack {
                            Circle()
                                .stroke(dc.isSelected ? Color.init("borderSelected") : Color("circleBorder"))
                                .frame(width: 18, height: 18)
                                .padding()

                            Circle()
                                .frame(width: 10, height: 10)
                                .foregroundColor(dc.isSelected ? Color.init("borderSelected"): Color.clear)
                        }
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

页面看起来像这样

rib*_*ynn 6

解决方案

改成。DCViewModel​struct

或者,如果您必须将其保留为 a class,请使其DCViewModel符合ObservableObject 并在每个 single 中保留单个引用View。(这意味着您应该将该行作为单个减去View)


解释

@Published 是一个属性包装器,仅当设置了包装值时才发布更改消息。

值类型和引用类型之间的区别:当您更改保存值类型(结构)的变量时,它实际上已被设置为新值。但是,当您更改引用类型(类)的值时,指向该对象的变量不会更改。

DCViewModel这就是为什么,在您的情况下,当您向(值类型)添加新值时Array,您总是为该数组设置一个新值,因此@Published会生效。然而,包装的值为DCViewModel,它是一个类(引用类型)。当您更改DCViewModel的值时,包装值的 setter 将不会被调用,也@Published不会发布消息。