I was experimenting with SwiftUI and came across a problem while implementing the data model for one of my List. My plan was to create a protocol CardProtocol as the data protocol for the elements of my lists and then have a CoreData implementation of the protocol as well as a dummy one for unit testing and Canvas use. If you are using a data collection in SwiftUI List the single elements need to conform to the Identifiable protocol.
The code looks like this:
import SwiftUI
import Combine
final class CardsModel: BindableObject {
var cards: [CardProtocol] = []
let didChange = PassthroughSubject<CardsModel, Never>()
}
protocol CardProtocol: Identifiable {
var id: Int { get set }
var firstName: String? { get set }
var lastName: String? { get set }
var email: String? { get set }
var phone: String? { get set }
}
This will not even compile as the Identifiable protocol has 2 associated types which needs to be specified if the protocol is to be used for a variable definition.
/// A type that can be compared for identity equality.
public protocol Identifiable {
/// A type of unique identifier that can be compared for equality.
associatedtype ID : Hashable
/// A unique identifier that can be compared for equality.
var id: Self.ID { get }
/// The type of value identified by `id`.
associatedtype IdentifiedValue = Self
/// The value identified by `id`.
///
/// By default this returns `self`.
var identifiedValue: Self.IdentifiedValue { get }
}
The exact error being error: protocol 'CardProtocol' can only be used as a generic constraint because it has Self or associated type requirements.
Now ID is not an issue and can be fixed, but IdentifiedValue it's by nature different in the CoreData and the dummy implementation.
The only reasonable solution that I found was to remove compliance to Identifiable from the protocol and reintroduce it later in the View using cardsModel.cards.identified(by: \.id). Is there any better way out of this, that let me keep the Identifiable compliance at protocol level?