ForEach 在一系列协议实现上?

Sha*_*man 7 foreach swift swiftui

我开始学习 SwiftUI,因此我决定编写一个简单的密码管理器作为学习练习。我protocol在密码中定义了通用属性:

protocol Secret: Codable {
    
    var id: String { get set }
    var name: String { get set }
    var createdDate: Date { get set }
    
    var favorite: Bool { get set }
    
    var category: SecretCategory { get set }
    
    var notes: String { get set }
    
    init(_ id: String, name: String)
    init(_ id: String, name: String, favorite: Bool)

}
Run Code Online (Sandbox Code Playgroud)

然后,我定义了几个 Swiftstruct来实现这一点protocol并定义各种类型的秘密的属性:

struct LoginSecret: Secret, Identifiable {
    
    var id: String
    var name: String
    var createdDate: Date = Date()
    
    var favorite: Bool = false
    
    var category: SecretCategory = .login
    
    var notes: String = ""
    
    var username: String = ""
    var encryptedPassword: String = ""
    
    var websiteURLs: [String] = []
    
    init(_ id: String, name: String) {
        self.id = id
        self.name = name
    }
    
    init(_ id: String, name: String, favorite: Bool) {
        self.id = id
        self.name = name
        self.favorite = favorite
    }
}
Run Code Online (Sandbox Code Playgroud)

...和...

struct BankAccountSecret: Secret, Identifiable {
    
    var id: String
    var name: String
    var createdDate: Date = Date()
    
    var favorite: Bool = false
    
    var category: SecretCategory = .bankAccounts
    
    var notes: String = ""
    
    var bankName: String = ""
    var nameOnAccount: String = ""
    var routingNumber: String = ""
    var accountNumber: String = ""
    
    var swift: String = ""
    var iban: String = ""
    
    var encryptedPIN: String = ""
    
    var branchPhoneNumber: String = ""
    var branchAddress: Address = Address()
    
    init(_ id: String, name: String) {
        self.id = id
        self.name = name
    }
    
    init(_ id: String, name: String, favorite: Bool) {
        self.id = id
        self.name = name
        self.favorite = favorite
    }
}
Run Code Online (Sandbox Code Playgroud)

这些工作得很好,我可以对 JSON 中的值进行编码/解码以便稍后显示。不过,现在我正在编写 SwiftUI 代码。我想显示 a 中的每个项目,并使用 SwiftUI 的List迭代Array对象。我的代码如下所示:SecretForEach

struct SecretsListView: View {

    @State    
    var secrets: [Secret]
    
    var body: some View {
        NavigationView {
            List {
               ForEach(secrets) { secret in
                  <snip>
               }
            }
        }
   }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我编译时,我收到一条错误消息...

Value of protocol type 'Secret' cannot conform to 'Identifiable'; only struct/enum/class types can conform to protocols
Run Code Online (Sandbox Code Playgroud)

有没有办法迭代对象数组Secret?有其他方法可以实现此目的吗?这个问题是 SwiftUI 特有的吗ForEach?我应该使用标准 SwiftArray forEach方法吗?非常感谢您提供的任何指导。我使用 Swift 和 UIKit 一段时间了,但 SwiftUI 是新的,我想确保我正在正确地为框架进行开发。

Dáv*_*tor 11

是的,只SwiftUI.ForEach要求Identifiable符合,Array.forEach不要求。

不过,还有其他几个初始化程序ForEach不需要您的模型类型符合Identifiable.

您可以使用init(_ data: Data, id: KeyPath<Data.Element, ID>, content: @escaping (Data.Element) -> Content)例如(假设ID符合Hashable,确实Secret.id如此,因为它是 a String)。

ForEach(secrets, id: \.id) { secret in
    <snip>
}
Run Code Online (Sandbox Code Playgroud)

另一种解决方案是将数组的索引传递给ForEach,然后您可以使用ForEach(secrets.indices),但由于您有一个可以用作 的Hashable属性,所以前一个是更好的解决方案。Secretid

  • 完美的!!我知道我缺少一些小东西。效果非常好! (2认同)