Estoy creando una aplicación que es similar en estructura al tutorial de Apple . Mi aplicación tiene un ListView, que navega a un DetailsView. El DetailsView se compone de un UIKit personalizado UIView, que envuelvo con un UIViewRepresentable. Hasta aquí todo bien.

Ahora tengo por ahora una lista (digamos, de direcciones) que instanciaré en la memoria, para ser reemplazada con datos centrales eventualmente. Puedo vincular (usando @EnvironmentObject) el List<Address> al ListView.

Donde estoy atascado es unir los elementos para cada DetailsView. El tutorial de Apple, mencionado anteriormente, hace algo que creo que no es genial, por alguna razón (que no puedo entender):

  1. Vincula List a la vista de detalles (usando @EnvironmentObject)
  2. Pasa el elemento (en el caso del tutorial de Apple, landmark, en mi caso, un address) a la vista de detalles
  3. Durante la actualización en respuesta a un gesto del usuario, busca efectivamente el elemento List para actualizar el elemento en la lista. Esto parece caro, especialmente si la lista es grande.

Aquí está el código para el # 3 que para mí es sospechoso:

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

En su código, self.landmarkIndex realiza una búsqueda lineal:

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

Lo que intento hacer es vincular el elemento directamente a DetailsView y hacer que las actualizaciones del elemento actualicen la lista. Hasta ahora, no he podido lograr esto.

¿Alguien sabe el camino correcto? Parece que la dirección a la que apunta el tutorial no se escala.

0
tng 15 abr. 2020 a las 06:11

2 respuestas

Aquí hay un ejemplo de enfoque para usar el enlace directamente al elemento del modelo Address

Suponiendo que hay un modelo de vista como, donde Address es Identifiable struct

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

Entonces, en algún lugar de ListView puedes usar lo siguiente

ForEach (Array(vm.addresses.enumerated()), id: \.element.id) { (i, address) in
    NavigationLink("\(address.title)", 
       destination: DetailsView(address: self.$vm.addresses[i])) // pass binding !!
}
0
Asperi 15 abr. 2020 a las 03:41

En lugar de pasar un objeto Landmark, puede pasar un Binding<Landmark>.

LandmarkList.swift: cambie la iteración de userData.landmark a sus índices para que pueda obtener el enlace. Luego pase la oferta a LandmarkDetail y LandmarkRow

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: cambie landmark en Binding<Landmark> y cambie el favorito según el enlace

    @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: Cambiar hito a Binding

@Binding var landmark: Landmark
0
sfung3 15 abr. 2020 a las 03:47