6

I need to declare a variable of type UIView which also conforms to MyProtocol:

protocol MyProtocol: class {
    func foobar()
}

class MyClass {
    var myView: UIView<MyProtocol>! // Error: Cannot specialize non-generic type 'UIView'
}

However I get the compiler error: Cannot specialize non-generic type 'UIView'.

I need to access methods on the variable from UIView and MyProtocol.

What is the correct variable declaration to support these requirements?

If it makes any difference, only UIView subclasses will implement the protocol. Currently I add protocol conformance via extensions.

I found this answer: https://stackoverflow.com/a/25771265/233602 but it's not clear if that answer is still the best option going in when writing in Swift 2.

Community
  • 1
  • 1
Andrew Ebling
  • 10,175
  • 10
  • 58
  • 75

4 Answers4

10

Make your class a generic class as follows,

protocol MyProtocol: class {
    func foobar()
}

class MyClass<T:MyProtocol where T:UIView> {
    var myView: T!
}

The error above says that UIView cannot specialise to protocol MyProtocol, so, the solution here would be to make your class a generic class which takes generic parameter which conforms to MyProtocol and is subclass of UIView.

Sandeep
  • 20,908
  • 7
  • 66
  • 106
5

Probably the best way to solve this is to use a protocol where all UIViews conform to:

protocol UIViewType {
    var view: UIView { get }
}

extension UIView: UIViewType {
    var view: UIView { return self }
}

// the variable
var myView: protocol<UIViewType, MyProtocol>

Use the view property to access UIView specific functionality.

Qbyte
  • 12,753
  • 4
  • 41
  • 57
  • 3
    Notable example of where this isn't adequate is if you need to pass an instance of this protocol to a function that takes `UIView`. – mxcl Mar 07 '17 at 18:35
1

Late to the party here, but SE-0156 (adopted by Swift 4) enables class and protocol composition in type declarations without requiring (resorting to?) generics.

protocol MyProtocol: class {
     func foobar()
}

class MyClass {
     var myView: (UIView & MyProtocol)!
}
mygzi
  • 1,303
  • 1
  • 11
  • 21
0

If it makes any difference, only UIView subclasses will implement the protocol.

It makes all the difference! Just do this:

protocol MyProtocol: UIView {
  func foobar()
}

class MyClass {
  var myView: MyProtocol!
}