Home > Net >  Can't use property of a protocol type once protocol has associated type [duplicate]
Can't use property of a protocol type once protocol has associated type [duplicate]

Time:09-29

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
    //...
}
  • Related