Bibek
Bibek

Reputation: 3719

Protocol 'BaseListPresenter' can only be used as a generic constraint because it has Self or associated type requirements

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

Answers (1)

Štěpán
Štěpán

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

Related Questions