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.