简体   繁体   中英

ForEach over an array of protocol implementations?

I'm starting to learn SwiftUI, and so I decided to write a simple password manager as a learning exercise. I've defined a protocol with the common attributes in my passwords:

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)

}

Then, I've defined a couple of Swift struct s that implement this protocol and define the properties of various types of secrets:

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

...and...

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

These work just fine, and I'm able to Encode/Decode values in JSON for display later. However, now I'm working on my SwiftUI code. I want to display each item in a List , iterating over an Array of Secret objects using SwiftUI's ForEach . My code looks like this:

struct SecretsListView: View {

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

However, when I compile I get an error saying...

Value of protocol type 'Secret' cannot conform to 'Identifiable'; only struct/enum/class types can conform to protocols

Is there no way to iterate over an array of Secret objects? Is there a different way to accomplish this? Is this issue specific to SwiftUI's ForEach ? Should I use the standard Swift Array forEach method instead? Any guidance you can provide is greatly appreciated. I've worked with Swift and UIKit for a while, but SwiftUI is new and I want to make sure I'm developing for the framework correctly.

Yes, only SwiftUI.ForEach requires the Identifiable conformance, Array.forEach does not require it.

There are several other initialisers of ForEach though that don't require your model type to conform to Identifiable .

You could use init(_ data: Data, id: KeyPath<Data.Element, ID>, content: @escaping (Data.Element) -> Content) for instance (assuming that ID conforms to Hashable , which Secret.id does, since it's a String ).

ForEach(secrets, id: \.id) { secret in
    <snip>
}

Another solution would be passing the indices of the array to ForEach , then you could use ForEach(secrets.indices) , but since you have a Hashable property on Secret that you can use as the id , that's a the previous one is a better solution.

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