Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

149
Vistas
Uso de una matriz de protocolos con ForEach y sintaxis enlazable

Tengo una matriz de protocolo @Published que estoy recorriendo con un ForEach para presentar los elementos en alguna vista. Me gustaría poder usar la sintaxis enlazable de SwiftUI con ForEach para generar un enlace para mí, de modo que pueda mutar cada elemento y reflejarlo en la matriz original.

Esto parece funcionar para las propiedades que se implementan en el protocolo, pero no estoy seguro de cómo accedería a las propiedades que son exclusivas del tipo de conformidad del protocolo. En el código de ejemplo a continuación, sería la propiedad de owner del Animal o la propiedad de age del Human . Pensé que podría ser necesario algún tipo de conversión de tipo, pero no puedo entender cómo retener la referencia a la matriz subyacente a través del enlace.

Avísame si necesitas más detalles.

 import SwiftUI protocol Testable { var id: UUID { get } var name: String { get set } } struct Human: Testable { let id: UUID var name: String var age: Int } struct Animal: Testable { let id: UUID var name: String var owner: String } class ContentViewModel: ObservableObject { @Published var animalsAndHumans: [Testable] = [] } struct ContentView: View { @StateObject var vm: ContentViewModel = ContentViewModel() var body: some View { VStack { ForEach($vm.animalsAndHumans, id: \AnyTestable.id) { $object in TextField("textfield", text: $object.name) // if the object is an Animal, how can I get it's owner? } Button("Add animal") { vm.animalsAndHumans.append(Animal(id: UUID(), name: "Mick", owner: "harry")) } Button("Add Human") { vm.animalsAndHumans.append(Human(id: UUID(), name: "Ash", age: 26)) } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Este es un problema espinoso con sus tipos de datos.

Si puede cambiar sus tipos de datos, puede hacer que esto sea más fácil de resolver.

Por ejemplo, tal vez pueda modelar sus datos de esta manera, usando una enum en lugar de un protocol para representar las variantes:

 struct Testable { let id: UUID var name: String var variant: Variant enum Variant { case animal(Animal) case human(Human) } struct Animal { var owner: String } struct Human { var age: Int } }

También ayudará agregar descriptores de acceso para los datos asociados de las dos variantes:

 extension Testable { var animal: Animal? { get { guard case .animal(let animal) = variant else { return nil } return animal } set { guard let newValue = newValue, case .animal(_) = variant else { return } variant = .animal(newValue) } } var human: Human? { get { guard case .human(let human) = variant else { return nil } return human } set { guard let newValue = newValue, case .human(_) = variant else { return } variant = .human(newValue) } } }

Entonces puedes escribir tu vista así:

 class ContentViewModel: ObservableObject { @Published var testables: [Testable] = [] } struct ContentView: View { @StateObject var vm: ContentViewModel = ContentViewModel() var body: some View { VStack { List { ForEach($vm.testables, id: \.id) { $testable in VStack { TextField("Name", text: $testable.name) if let human = Binding($testable.human) { Stepper("Age: \(human.wrappedValue.age)", value: human.age) } else if let animal = Binding($testable.animal) { HStack { Text("Owner: ") TextField("Owner", text: animal.owner) } } } } } HStack { Button("Add animal") { vm.testables.append(Testable( id: UUID(), name: "Mick", variant: .animal(.init(owner: "harry")) )) } Button("Add Human") { vm.testables.append(Testable( id: UUID(), name: "Ash", variant: .human(.init(age: 26)) )) } } } } }
over 4 years ago · Santiago Trujillo Denunciar

0

Una forma simple de resolver es extender su protocolo Testable . algo le gusta

 protocol Testable { var id: UUID { get } var name: String { get set } var extra: String? { get } } struct Human: Testable { let id: UUID var name: String var age: Int var extra: String? { nil } } struct Animal: Testable { let id: UUID var name: String var owner: String var extra: String? { return owner } }

Su bloque ForEach no necesita saber el tipo concreto: Animal o Human , solo verifique el extra de Testable para decidir agregar un nuevo elemento o no.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda