简体   繁体   中英

SwiftUI - View showing Elements conforming to a Protocol and ForEach over them

I want to write a SwiftUI View ListOfMyStruct that operates on an Array of Elements conforming to a given Protocol MyProtocol .
The example works, but of course I need to ForEach over the Elements of the Array (as tried in the commented out lines).
Using ForEach, I get: Value of protocol type 'MyProtokoll' cannot conform to 'Hashable'; only struct/enum/class types can conform to protocols .
If I try to let MyProtocol conform to Hashable I get: Protocol 'MyProtokoll' can only be used as a generic constraint because it has Self or associated type requirements .

How can I archive this?

struct PTest: View {
  @State var allMyStruct : [MyStruct] =
    [ MyStruct(name: "Frank Mueller", myshortName: "fm", a_lot_of_other_sttributes: "bla"),
      MyStruct(name: "Tom Smith", myshortName: "ts", a_lot_of_other_sttributes: "bla")
    ]

  var body: some View {
    VStack {
      Text("Hello, world!")
      ListOfMyStruct(elements: allMyStruct)
    }
    .frame(width: 400, height: 400, alignment: .center)
    .padding()
  }
}

struct ListOfMyStruct: View {
  var elements : [MyProtokoll]

  var body: some View {

    HStack {
      Text("Elements of MyProtocol: ")
      Text("\(elements[0].shortName() )")
      Text("\(elements[1].shortName() )")

//      ForEach(elements, id: \.self) { myProtocol in
//        Text("\(myProtocol.shortName())")
//      }
    }
  }
}


//protocol MyProtokoll : Identifiable, Hashable  {
protocol MyProtokoll {
  var id: String { get }
  func shortName() -> String
}

struct MyStruct :MyProtokoll {

  var id : String {myshortName}
  var name : String
  var myshortName :String
  var a_lot_of_other_sttributes : String

  func shortName() -> String {
    myshortName
  }
}

It is possible to use iteration by indices.

Here is a fixed part (tested with Xcode 12.4)

    HStack {
//      Text("Elements of MyProtocol: ")
//      Text("\(elements[0].shortName() )")
//      Text("\(elements[1].shortName() )")

        ForEach(elements.indices, id: \.self) { i in
           Text("\(elements[i].shortName())")
        }
    }

also the solution is to specify id explicitly, like

  ForEach(elements, id: \.id) { myProtocol in
    Text("\(myProtocol.shortName())")
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM