简体   繁体   English

SwiftUI - 显示符合协议的元素并为元素使用 == 的视图

[英]SwiftUI - View showing Elements conforming to a Protocol and and using == for the Elements

I need to display arrays of different structs, conforming to a common Protocol, in a View.我需要在视图中显示符合通用协议的不同结构的 arrays。
As advised in SwiftUI - View showing Elements conforming to a Protocol and ForEach over them I tried like this - it works fine!正如SwiftUI 中所建议的 - 查看显示符合协议的元素和 ForEach 在它们之上我尝试过这样 - 它工作正常!

Now I need to check elements of the array for Equality.现在我需要检查数组的元素是否相等。
Letting the Protocol conform to Equatable does not compile -让协议符合Equatable不会编译 -
It gets the error: Protocol 'Suggest' can only be used as a generic constraint because it has Self or associated type requirements .它得到错误: Protocol 'Suggest' can only be used as a generic constraint because it has Self or associated type requirements

//protocol Suggest :Equatable {
protocol Suggest  {
  var desc: String { get }
}

struct Person : Suggest {
  var surname : String
  var name: String
  
  var id: String { return name }
  var desc: String { return name }
}

struct Book : Suggest {
  var titel : String
  var abstact : String
  
  var id: String { return titel }
  var desc: String { return titel }
}


let books = [ Book(titel: "book 1", abstact: "abstract1"),
              Book(titel: "book 2", abstact: "abstract2")
            ]

let persons = [ Person(surname: "John", name: "Doe"),
                Person(surname: "Susan", name: "Smith"),
                Person(surname: "Frank", name: "Miller")
              ]


struct ContentView: View {
  var body: some View {
    VStack {
      SuggestList(list: books)
      SuggestList(list: persons)
    }
  }
}

struct SuggestList: View {
  var list : [Suggest]
// this line does not compile, if Suggest conforms to Equitable
// "Protocol 'Suggest' can only be used as a generic constraint because it has Self or associated type requirements" 
  
  var body: some View {
    List(list.indices, id: \.self) { index in
      Text(list[index].desc)
//        .onTapGesture {
//          if list.contains(list[index]){print ("hello")}
//        }
    }
  }
}

you need use <SuggestType: Suggest> and also make Suggest protocol Equatable and then use and define == in Person and Book您需要使用<SuggestType: Suggest>并让Suggest协议Equatable ,然后在PersonBook中使用和定义==


struct ContentView: View {
    var body: some View {
        VStack {
            SuggestList(list: books)
            SuggestList(list: persons)
        }
    }
}

protocol Suggest: Equatable  {
    var desc: String { get }
}

struct Person: Suggest {
    
    var surname: String
    var name: String
    
    var id: String { return name }
    var desc: String { return name }
    
    
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name
    }
    
}

struct Book: Suggest {
    
    var titel: String
    var abstact: String
    
    var id: String { return titel }
    var desc: String { return titel }
    
    static func == (lhs: Book, rhs: Book) -> Bool {
        return lhs.titel == rhs.titel
    }
    
    
}



let persons = [Person(surname: "John", name: "Doe"),
               Person(surname: "Susan", name: "Smith"),
               Person(surname: "Frank", name: "Miller")]


let books = [Book(titel: "book 1", abstact: "abstract1"),
             Book(titel: "book 2", abstact: "abstract2")]




struct SuggestList<SuggestType: Suggest>: View {
    
    var list : [SuggestType]

    
    var body: some View {
        List(list.indices, id: \.self) { index in
            Text(list[index].desc)
                .onTapGesture {
                    if list.contains(list[index]){ print(list[index].desc) }
                }
        }
    }
}

This Answer is belong to question in comments part!这个答案属于评论部分的问题! About Equatable function.关于Equatable function。

If you do not define Equatable function explicitly, then Xcode would take care itself if it can infer it by itself, some times in complex struct it will ask you to show it when instance of your struct are equal, but when you define Equatable function explicitly Xcode would apply your custom rule, for example I create 2 type of Person, which in first one PersonV1 we did not define == for it but in second one PersonV2 we did defined! If you do not define Equatable function explicitly, then Xcode would take care itself if it can infer it by itself, some times in complex struct it will ask you to show it when instance of your struct are equal, but when you define Equatable function explicitly Xcode 将应用您的自定义规则,例如,我创建了 2 种类型的人,在第一个PersonV1 中我们没有为它定义== ,但在第二个PersonV2 中我们确实定义了! So Xcode would be taking all persons with same name equal in PersonV2 if even they have deferent surname .所以 Xcode 将在PersonV2中取所有同名的人,即使他们有不同的surname try this down code for more real testing example.试试这个代码以获得更真实的测试示例。 And any update for surname in PersonV2 would not take any place, because it does not count in determine if 2 instance of PersonV2 are equal or not!并且PersonV2姓氏的任何更新都不会发生,因为它不计入确定PersonV2的 2 个实例是否相等! Once you initialized an instance of PersonV2 , the surname will not be updatable anymore.初始化PersonV2的实例后,姓氏将不再可更新。 you can try to update but it will not applied because in make no deference if this instance is the same or not!您可以尝试更新,但它不会应用,因为如果此实例是否相同,则不予考虑!

Notice: We could make PersonV2 equality function to re act to surname change as well with this code, but I think you want to work just with name like in your question :注意:我们可以使PersonV2相等 function 也可以使用此代码对姓氏更改做出反应,但我认为您只想使用问题中的名称

static func == (lhs: PersonV2, rhs: PersonV2) -> Bool {
    return lhs.name == rhs.name && lhs.surname == rhs.surname
}



struct ContentView: View {

    @State private var person1: PersonV1 = PersonV1(surname: "Frank", name: "Miller")
    @State private var person2: PersonV2 = PersonV2(surname: "John", name: "Doe")

    var body: some View {
        
        VStack(spacing: 50.0) {
        
        VStack(spacing: 20.0) {

            Button("update name of person1") { person1.name += " updated!" }
            Button("update surname of person1") { person1.surname += " updated!" }

        }
        .padding()
        .background(Color.yellow)
        .onChange(of: person1) { newValue in print("onChange for person1:", newValue) }
        
        
        
        
        VStack(spacing: 20.0) {

            Button("update name of person2") { person2.name += " updated!" }
            Button("update surname of person2") { person2.surname += " updated!" }

        }
        .padding()
        .background(Color.red)
        .onChange(of: person2) { newValue in print("onChange for person2:", newValue) }
        
        }
        
    }
}

protocol Suggest: Equatable  {
    var desc: String { get }
}



struct PersonV1: Suggest {
    
    var surname: String
    var name: String
    
    var id: String { return name }
    var desc: String { return name }
   
}


struct PersonV2: Suggest {
    
    var surname: String
    var name: String
    
    var id: String { return name }
    var desc: String { return name }

    static func == (lhs: PersonV2, rhs: PersonV2) -> Bool {
        return lhs.name == rhs.name
    }
    
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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