Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

147
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda