【问题标题】:SwiftUI - View showing Elements conforming to a Protocol and and using == for the ElementsSwiftUI - 显示符合协议的元素并为元素使用 == 的视图
【发布时间】:2021-04-18 16:17:22
【问题描述】:

我需要在视图中显示符合通用协议的不同结构的数组。
正如SwiftUI - View showing Elements conforming to a Protocol and ForEach over them 中所建议的那样,我尝试过这样 - 效果很好!

现在我需要检查数组的元素是否相等。
让协议符合Equatable 不会编译 -
它得到错误: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")}
//        }
    }
  }
}

【问题讨论】:

    标签: swift swiftui swift-protocols


    【解决方案1】:

    您需要使用<SuggestType: Suggest> 并制作Suggest协议Equatable,然后在Person中使用并定义== strong> 和 图书


    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) }
                    }
            }
        }
    }
    

    【讨论】:

    • Tnx!关于您的答案的一个问题。如果您没有在 Person 和 Book 中定义 'static func ==',它仍然符合要求。在这种情况下使用什么函数来进行公平性检查?
    • 这是个好问题,我认为 Xcode 会推断它,或者在我个人的情况下,在其他应用程序中,xcode 会要求定义它应该如何检查它,但我不确定我说的是什么,当你使用像 Int 或 String 这样的简单数据结构,xcode 会找到它的方式,但对于更复杂的更好地定义它。
    • @mica:关于你提出的问题,我也举例回答了。
    【解决方案2】:

    这个答案属于cmets部分的问题!关于Equatable函数。

    如果你没有显式定义 Equatable 函数,那么 Xcode 会自行推断,如果它可以自己推断它,有时在复杂结构中它会要求你在结构实例相等时显示它,但是当你定义Equatable 函数显式 Xcode 将应用您的自定义规则,例如我创建了 2 种类型的人,在第一个 PersonV1 我们没有为它定义 == 但在第二个PersonV2 我们确实定义了!因此 Xcode 会在 PersonV2 中将所有同名的人视为相同,即使他们有不同的 surname。试试这个代码以获得更真实的测试示例。并且 PersonV2surname 的任何更新都不会发生,因为它不计入确定 PersonV2 的 2 个实例是否相等!初始化 PersonV2 的实例后,surname 将不再可更新。你可以尝试更新,但它不会应用,因为不管这个实例是否相同!

    注意:我们可以使用此代码使 PersonV2 相等函数来响应姓氏更改,但我认为您只想使用名称就像你的问题一样

    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
        }
        
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多