在典型列表中管理SwiftUI状态->详细信息应用

时间:2020-04-15 03:11:28

标签: swift swiftui

我正在构建一个结构与Apple tutorial类似的应用。我的应用程序有一个ListView,它可以导航到DetailsViewDetailsViewUIKit自定义UIView组成,我将其与UIViewRepresentable包装在一起。到目前为止,一切都很好。

现在,我现在有一个在内存中实例化的列表(比方说,地址),最终将被核心数据替换。我可以将@EnvironmentObject绑定(使用List<Address>ListView

我遇到的问题是为每个DetailsView绑定元素。上面引用的Apple教程做了一些我认为不好的事情-由于某种原因(我不知道),它是:

  1. List绑定到详细信息视图(使用@EnvironmentObject
  2. 将元素(在Apple教程中为landmark,在我的情况下为address)传递到详细信息视图
  3. 在响应用户手势进行更新期间,它有效地在List中搜索元素,以更新列表中的元素。这似乎很昂贵,尤其是如果列表很大。

以下是我怀疑的#3的代码:

    Button(action: {
        self.userData.landmarks[self.landmarkIndex].isFavorite.toggle()
    }) 

在他们的代码中,self.landmarkIndex进行线性搜索:

    var landmarkIndex: Int {
        userData.landmarks.firstIndex(where: { $0.id == landmark.id })!
    }

我要做的是将元素直接绑定到DetailsView,并对该元素进行更新以更新列表。到目前为止,我还无法实现这一目标。

有人知道正确的方法吗?看来本教程所指向的方向无法扩展。

2 个答案:

答案 0 :(得分:1)

您可以传递Landmark而不是传递Binding<Landmark>对象。

LandmarkList.swift:将迭代从userData.landmark更改为其索引,以便获取绑定。然后将出价传递到LandmarkDetailLandmarkRow

struct LandmarkList: View {
    @EnvironmentObject private var userData: UserData

    var body: some View {
        NavigationView {
            List {
                Toggle(isOn: $userData.showFavoritesOnly) {
                    Text("Show Favorites Only")
                }

                ForEach(userData.landmarks.indices) { index in
                    if !self.userData.showFavoritesOnly || self.userData.landmarks[index].isFavorite {
                        NavigationLink(
                            destination: LandmarkDetail(landmark: self.$userData.landmarks[index])
                                .environmentObject(self.userData)
                        ) {
                            LandmarkRow(landmark: self.$userData.landmarks[index])
                        }
                    }
                }
            }
            .navigationBarTitle(Text("Landmarks"))
        }
    }
}

LandmarkDetail.swift:将landmark更改为Binding<Landmark>,然后根据绑定切换收藏夹

    @Binding var landmark: Landmark
.
.
.
                    Button(action: {
                        self.landmark.isFavorite.toggle()
                    }) {
                        if self.landmark
                            .isFavorite {
                            Image(systemName: "star.fill")
                                .foregroundColor(Color.yellow)
                        } else {
                            Image(systemName: "star")
                                .foregroundColor(Color.gray)
                        }
                    }

LandmarkRow.swift:将界标更改为Binding

@Binding var landmark: Landmark

答案 1 :(得分:0)

以下是直接对模型Address项目使用绑定的方法示例

假设有一个类似的视图模型,其中AddressIdentifiable结构

class AddressViewModel: ObservableObject {
    @Published var addresses: [Address] = []
}

因此,在ListView中的某个地方,您可以使用以下

ForEach (Array(vm.addresses.enumerated()), id: \.element.id) { (i, address) in
    NavigationLink("\(address.title)", 
       destination: DetailsView(address: self.$vm.addresses[i])) // pass binding !!
}