Peter Warbo
Peter Warbo

Reputation: 11710

Reference to class that conforms to a protocol

Let's say I have a protocol that looks like this:

protocol Foo {
    var bar: Bool { get set }
}

Now I have my view controller that conforms to the Foo protocol;

class FooViewController: UIViewController, Foo {
    ...
}

In another class I want to do something like this:

class FooClass {

    var viewController: UIViewController? // this should conform to Foo protocol

    func setViewController(viewController: UIViewController) {
        if let fooVC = viewController as? Foo {
            // viewController implements Foo protocol
            self.viewController = fooVC
        } else {
            print("ViewController does not conform to Foo protocol")
        }
    }
}

In Objective-C I would have a reference that looks like: UIViewController<Foo> *vc saying that vc is an object of class UIViewController conforming to Foo protocol. Is there a Swift equivalent?

EDIT: I guess it's not possible :(

Upvotes: 4

Views: 1336

Answers (4)

I. Pedan
I. Pedan

Reputation: 255

This is the solution:

typealias FooController = UIViewController & Foo

class FooClass {

    var viewController: FooController?

    func setViewController(viewController: FooController) {
        self.viewController = viewController
    }
}

Upvotes: 3

Wallace Campos
Wallace Campos

Reputation: 1301

Warning: This solution may become very painful.

As a workaround, you may use protocol compositions and eventually extensions.

In your example you could be interested only in UIResponder protocol methods which UIViewController conforms to.

typealias FooController = protocol<UIResponder, Foo>

class FooClass {

  var viewController: FooController?

  func setViewController(viewController: FooController) {
    // viewController implements UIResponder and Foo protocols
  }
}

But UIViewController has properties and methods that does not conforms to any protocol. In this case, you could make a protocol containing the methods that you want and extend UIViewController.

protocol ViewEvent {
  func viewWillAppear(animated: Bool)
  func viewDidAppear(animated: Bool)
  func viewWillDisappear(animated: Bool)
  func viewDidDisappear(animated: Bool)
}

extension UIViewController: ViewEvent {}

typealias FooController = protocol<UIResponder, ViewEvent, Foo>

Upvotes: 3

Luca Angeletti
Luca Angeletti

Reputation: 59496

I see what you mean.

I don't think you can declare a variable of a given class type and conform to a protocol.

However if you just need to check whether viewController does conform to the Foo protocol (and you don't really need to use the bar property declared in Foo) then you could do this.

func setViewController(viewController: UIViewController) {
    if viewController is Foo {
        self.viewController = viewController
    } else {
        print("ViewController does not conform to Foo protocol")
    }
}

Upvotes: 1

Pradeep K
Pradeep K

Reputation: 3661

You can define as viewController:Foo?

Based on our comment you should used if let fooVC = viewController as? FooViewController. If you are optional binding the viewController to Foo then assigning it to a UIViewController instance will not work.

Upvotes: 0

Related Questions