11

I would like to make a property that is of a certain type and also conforms to a protocol, which I would have done in Objective-C like this:

@property (nonatomic) UIViewController<CustomProtocol> *controller;

What I am looking for is to specify that the property can be set with an object of type UIViewController that also conforms to CustomProtocol, so that it's clear what the base class is. I know I could probably just use a short class stub to get the same results, i.e.

class CustomViewController : UIViewController, CustomProtocol {}

But this doesn't seem like the cleanest way to do it.

nhgrif
  • 61,578
  • 25
  • 134
  • 173
sashimiblade
  • 620
  • 7
  • 21

2 Answers2

11

This is now possible using the built-in composition:

var children = [UIViewController & NavigationScrollable]()

jwswart
  • 1,226
  • 14
  • 16
8

I can't think of a good way to express this in Swift. The syntax for a type is:

type → array-type­ | dictionary-type­ | function-type­ | type-identifier­ | tuple-type­ | optional-type­ | implicitly-unwrapped-optional-type­ | protocol-composition-type­ | metatype-type­

What you're looking for would be a kind of protocol-combination-type that also accepts a base class. (Protocol-combination-type is protocol<Proto1, Proto2, Proto3, …>.) However, this is not currently possible.

Protocols with associated type requirements are allowed to have typealiases that specify a required base class and required protocols, but these also require the types to be known at compile-time, so it's unlikely to be a viable option for you.

If you're really into it, you can define a protocol with the parts of the interface of UIViewController that you use, use an extension to add conformance, and then use protocol<UIViewControllerProtocol, CustomProtocol>.

protocol UIViewControllerProtocol {
    func isViewLoaded() -> Bool
    var title: String? { get set }
    // any other interesting property/method
}

extension UIViewController: UIViewControllerProtocol {}

class MyClass {
    var controller: protocol<UIViewControllerProtocol, CustomProtocol>
}
zneak
  • 134,922
  • 42
  • 253
  • 328
  • Indeed. This is what we should be doing. Just define a protocol that has everything we would possibly need, and extend things like `UIViewController`, which already implement all of these methods, as conforming to the protocol. – nhgrif Apr 26 '15 at 19:02
  • 1
    I went with just making the class stub, as I was developing further it actually turned out to make more sense for me than sticking to the protocol. Thanks! – sashimiblade Apr 27 '15 at 20:13
  • But how would you pass your `var controller` to a UIKit method that expects UIViewControllers, not UIViewController protocols? For example `navigiationController?.viewControllers = [controller]` – Daniel R Apr 05 '16 at 22:25
  • 1
    @DanielR, you're going to have to cast them. – zneak Apr 05 '16 at 23:32