I've started creating a base repository class which will hold data for each data model, but also I want it to be as generic as possible. I also need protocol to inform the consumer of this repository about the changes in in. Idea is to also have generic data change mechanism, and not define 20 protocols based on the data type. The code looks like this:
protocol BaseRepositoryDelegate {
associatedtype dataType
func didUpdateData(allData: [dataType], currentPage: [dataType], totalDataCount: Int, tag: Int?)
func didGetError(error: ApiError)
}
class BaseRepository<T> {
typealias dataType = T
var delegate: BaseRepositoryDelegate?
var tag: Int?
private(set) public var data = [T]()
private(set) public var currentPage = 0
private(set) public var totalCount = 0
init(delegate: BaseRepositoryDelegate, tag: Int? = nil) {
self.delegate = delegate
self.tag = tag
}
}
Problem I have is that delegate
property results in an error stating Protocol 'BaseRepositoryDelegate' can only be used as a generic constraint because it has Self or associated type requirements
and I am unable to resolved that one and keep the generic functionality of both the repository class and the base protocol. Any ideas on how to approach this?
My end goal of this would be to have a class that is SpecificRepository
that can inherit BaseRepository
and somehow provide a param that can define dataType for both Protocol and the BaseRepository
.
class SpecificRepository: BaseRepository<MySpecificType> {
typealias dataType = MySpecificType
// I can override methods here or properties based
// on my use-case, or I can add specific functionality.
}
CodePudding user response:
As the error message suggest, make it a generic type instead. Also the typealias declaration is pointless since you don't use it and it has no connection with the protocol. Connect T with the associated type of the protocol bye adding a where
condition to the class declaration (I also renamed T to DataType)
class BaseRepository<DataType, Delegate: BaseRepositoryDelegate> where Delegate.dataType == DataType{
typealias dataType = DataType
var delegate: Delegate?
var tag: Int?
private(set) public var data = [DataType]()
private(set) public var currentPage = 0
private(set) public var totalCount = 0
init(delegate: Delegate, tag: Int? = nil) {
self.delegate = delegate
self.tag = tag
}
}
Simple example
struct RepoDelegate: BaseRepositoryDelegate {
typealias dataType = Int
func didUpdateData(allData: [Int], currentPage: [Int], totalDataCount: Int, tag: Int?) {}
func didGetError(error: ApiError) {}
}
let delegate = RepoDelegate()
let repo = BaseRepository(delegate: delegate, tag: nil)
To use this for a sub-class you need to define for what data type and delegate type you are extending the base class
SpecificRepository: BaseRepository<MySpecificType, SpecificRepoDelegate>
where we match the type for the delegate
struct SpecificRepoDelegate: BaseRepositoryDelegate {
typealias dataType = MySpecificType
//...
}