3

I want to create a base class for UIViews that require that a delegate conform to a specific protocol defined by the View.

class BaseView<P>: UIView {
    weak var delegate: P?
}

protocol MyProtocol {}

class MyView: BaseView<MyProtocol> {}

This gives me the error: "'weak' must not be applied to non-class-bound 'T'; consider adding a protocol conformance that has a class bound".

How do I fix this error? Or is there some work around? Or is it not so necessary to make the delegate variable weak in the first place? Thanks in advance.

Myk
  • 979
  • 6
  • 16

2 Answers2

5

Since weak is a property assigned to anything that is of class type and not struct, you have to explicitly constraint your generic parameter to be of class type and you do that this way:

class BaseView<P: AnyObject>: UIView {
    weak var delegate: P?
}

@objc protocol MyProtocol {

}

class MyView: BaseView<MyProtocol> {

}

Only one need of clarification. Usually to make a protocol be of class type usally you would make it conform to class this way:

protocol MyProtocol: class { }

However, for some reason the compiler throws an error if you were to do it that way. I learned that this is a bug that could be learned about more here:

How to require that a protocol can only be adopted by a specific class

So adding the @objc helps silence the warning and error both.

Serj
  • 696
  • 5
  • 17
1

You should add type constraint to your generic by adding MyProtocol and create a class that conforms MyProtocol.

You can find more info here.

Updated code:

class BaseView<P: MyProtocol>: UIView {
    weak var delegate: MyProtocol?
}

protocol MyProtocol: class {}

class MyProtocolImp: MyProtocol {

}

class MyView: BaseView<MyProtocolImp> {

}

But I don't know why you use P parameter in class. You can write without this:

class BaseView: UIView {
    weak var delegate: MyProtocol?
}

protocol MyProtocol: class {}

class MyView: BaseView {

}
Ivan Smetanin
  • 1,999
  • 2
  • 21
  • 28
  • I don't think this will work for me. I want to be able to reuse MyView with multiple class types (that conform to MyProtocol) whereas in your example it can only be used with class MyProtocolImp. Thanks for your answer, and please correct me if I'm wrong. – Myk May 27 '18 at 17:42
  • @Myk Just use second example. There are you can use any class that conforms `MyProtocol` as `delegate` – Ivan Smetanin May 27 '18 at 18:00
  • Then I'm limited to using just one protocol. What I want is to have multiple different views, for example a blue view and a red view. I want both blue view and red view to have their own protocols that a delegate must conform to. So RedViewController: RedProtocol and BlueViewController: BlueProtocol. This way I can create class blueView: BaseView and redView: BaseView and pass in the protocol rather than the view. How can I make this work with your second method? It seems like I would only be able to set the delegate to one specific kind of protocol. – Myk May 27 '18 at 18:47