Reputation: 3719
I am defining a protocol that has certain functions and variables
protocol BaseListPresenter {
associatedtype T
var values: [T] {get}
}
extension BaseListPresenter {
public func count() -> Int {
return values.count
}
public func valueAtIndex(index: Int) -> T? {
return values[index]
}
}
Now, I want to use this in a class:
class X: UIViewController {
var listPresenter: BaseListPresenter? // HERE it gives me error
// some other functions and variables here
}
Got Error in above saying: Protocol 'BaseListPresenter' can only be used as a generic constraint because it has Self or associated type requirements
Now, I define sub-class of X:
class Y: X {
func setPresenter() {
self.listPresenter = UsersPresenter() // UsersPresenter confirms BaseListPresenter protocol with value's type "User"
}
// many more functions below
}
class Z: X {
func setPresenter() {
self.listPresenter = RoomsPresenter() // RoomsPresenter confirms BaseListPresenter protocol with value's type "Room"
}
// many more functions below
}
I have achieved solution from (Protocol can only be used as a generic constraint because it has Self or associatedType requirements) already by creating UsersPresenter and RoomsPresenter. However, I want to create BaseListPresenter type variable which will take different types of value in X (a UIViewController); once Room and next time User depending on subclass of X.
How can I solve this issue and use as I want?
Upvotes: 0
Views: 2128
Reputation: 348
Problem is, that the associated type of your protocol has to be determined when the protocol is used somewhere. In your implementation of class X
, the compilator has no idea, what type the T
is.
I would implement it this way:
class X<TPresenter : BaseListPresenter>: UIViewController {
var listPresenter: TPresenter? // HERE it gives me error
// some other functions and variables here
}
Then specialize X
when derive:
class Y: X<UsersPresenter> {
func setPresenter() {
self.listPresenter = UsersPresenter() // UsersPresenter confirms BaseListPresenter protocol with value's type "User"
}
// many more functions below
}
class Z: X<RoomsPresenter> {
func setPresenter() {
self.listPresenter = RoomsPresenter() // RoomsPresenter confirms BaseListPresenter protocol with value's type "Room"
}
// many more functions below
}
This construct works.
Note: Using generics in UIViewController derived classes caused me some troubles about an year ago. Xcode/compiler was somehow unable to link the generic controller with the scene in storyboard. It did not cause compile errors, but it did not work during runtime - spent hours of diagnosing.
Upvotes: 0