Swift 5 update
In Swift 5 (Xcode 10.2), your code now works as expected without having to perform a force cast.
In Swift 4.x, Swift doesn't fully support superclass constraints on protocols, that is, being able to define protocol P where Self : C where C is the type of a class.
The fact that the compiler doesn't prevent you from doing this until the feature is actually implemented was an oversight, as said by Swift compiler engineer Slava Pestov:
Slava Pestov added a comment - 31 May 2018 1:19 PM
[...] "protocol P : Foo where Self : Class" was discovered on accident by users, and it doesn't really work completely. It was an oversight that it wasn't banned.
However this is a feature that is intended to be fully implemented in a future version of the language as a part of SE-0156.
Slava Pestov added a comment - 31 May 2018 1:19 PM
Both are supposed to work, but we haven't fully implemented the proposal yet.
(Edit: Slava has now implemented this in #17611, #17651, #17816 & #17851, so you'll get them in Swift 5, available from Xcode 10.2)
Once implemented, you'll be able to treat such a protocol type as the class type that it requires conforming types to inherit from (e.g allowing you to treat your Fooable as a UIViewController without having to cast), in the same way that you can treat a class existential such as Fooable & UIViewController as a UIViewController.
Not only that, but you'll also be able to state the superclass requirement directly on the protocol rather than in a where clause, for example:
protocol Fooable : UIViewController {
func foo()
}
However, until Swift 5, I would recommend steering well clear of superclass constrained protocols – they currently have some nasty rough edges around them.
For example, this will miscompile and crash at runtime in Swift 4.1:
class C : P {
func speak() {}
}
protocol P where Self : C {
func speak()
}
let c: P = C()
c.speak()
and it'll crash the compiler in later versions of the language (SR-6816).
As a workaround, you could use an underscored protocol with a class existential typealias in order to enforce the class constraint instead. For example:
import UIKit
protocol _Fooable : class {
func foo()
}
typealias Fooable = _Fooable & UIViewController
class SampleViewController : Fooable /* implicitly : UIViewController */ {
func foo() {
print("foo")
}
}
// ...
let vc1: Fooable = SampleViewController()
let vc2: Fooable = SampleViewController()
vc1.show(vc2, sender: nil)