In Swift, how can I declare a variable of a specific type that conforms to one or more protocols?

In Swift 4 it is now possible to declare a variable that is a subclass of a type and implements one or more protocols at the same time.

var myVariable: MyClass & MyProtocol & MySecondProtocol

To do an optional variable:

var myVariable: (MyClass & MyProtocol & MySecondProtocol)?

or as the parameter of a method:

func shakeEm(controls: [UIControl & Shakeable]) {}

Apple announced this at WWDC 2017 in Session 402: Whats new in Swift

Second, I want to talk about composing classes and protocols. So, here I've introduced this shakable protocol for a UI element that can give a little shake effect to draw attention to itself. And I've gone ahead and extended some of the UIKit classes to actually provide this shake functionality. And now I want to write something that seems simple. I just want to write a function that takes a bunch of controls that are shakable and shakes the ones that are enabled to draw attention to them. What type can I write here in this array? It's actually frustrating and tricky. So, I could try to use a UI control. But not all UI controls are shakable in this game. I could try shakable, but not all shakables are UI controls. And there's actually no good way to represent this in Swift 3. Swift 4 introduces the notion of composing a class with any number of protocols.


You cannot declare variable like

var object:Base,protocol<ProtocolOne,ProtocolTwo> = ...

nor declare function return type like

func someFunc() -> Base,protocol<MyProtocol,Protocol2> { ... }

You can declare as a function parameter like this, but it's basically up-casting.

func someFunc<T:Base where T:protocol<MyProtocol1,MyProtocol2>>(val:T) {
    // here, `val` is guaranteed to be `Base` and conforms `MyProtocol` and `MyProtocol2`
}

class SubClass:BaseClass, MyProtocol1, MyProtocol2 {
   //...
}

let val = SubClass()
someFunc(val)

As of now, all you can do is like:

class CellFactory {
    class func createCellForItem(item: SpecialItem) -> UITableViewCell {
        return ... // any UITableViewCell subclass
    }
}

let cell = CellFactory.createCellForItem(special)
if let asProtocol = cell as? protocol<MyProtocol1,MyProtocol2> {
    asProtocol.protocolMethod()
    cell.cellMethod()
}

With this, technically cell is identical to asProtocol.

But, as for compiler, cell has interface of UITableViewCell only, while asProtocol has only protocols interface. So, when you want to call UITableViewCell's methods, you have to use cell variable. When you want to call protocols method, use asProtocol variable.

If you are sure that cell conforms to protocols you don't have to use if let ... as? ... {}. like:

let cell = CellFactory.createCellForItem(special)
let asProtocol = cell as protocol<MyProtocol1,MyProtocol2>

Unfortunately, Swift does not support object level protocol conformance. However, there is a somewhat awkward work-around that may serve your purposes.

struct VCWithSomeProtocol {
    let protocol: SomeProtocol
    let viewController: UIViewController

    init<T: UIViewController>(vc: T) where T: SomeProtocol {
        self.protocol = vc
        self.viewController = vc
    }
}

Then, anywhere you need to do anything that UIViewController has, you would access the .viewController aspect of the struct and anything you need the protocol aspect, you would reference the .protocol.

For Instance:

class SomeClass {
   let mySpecialViewController: VCWithSomeProtocol

   init<T: UIViewController>(injectedViewController: T) where T: SomeProtocol {
       self.mySpecialViewController = VCWithSomeProtocol(vc: injectedViewController)
   }
}

Now anytime you need mySpecialViewController to do anything UIViewController related, you just reference mySpecialViewController.viewController and whenever you need it to do some protocol function, you reference mySpecialViewController.protocol.

Hopefully Swift 4 will allow us to declare an object with protocols attached to it in the future. But for now, this works.

Hope this helps!