greg3z
greg3z

Reputation: 601

Swift protocol defines an init that doesn't work for UIViewController

Here is a simple protocol:

protocol StringsInitiable {
    init(strings: [String])
}

Trying to use the initializer in an extension works when constraint to NSObject...

extension StringsInitiable where Self: NSObject {
    func test() {
        let _ = Self(strings: [])
    }
}

...but not when constraint to UIViewController. It then complains that the initializer should be labeled 'coder', referring to the mandatory initializer from NSCoding.

extension StringsInitiable where Self: UIViewController {
    func test() {
        let _ = Self(strings: []) // error label 'strings:' expected 'coder:'
    }
}

Is there a way to use the initializer declared in the protocol even when being a UIViewController subclass?

EDIT

It seems to be working when constraining the extension to a base class (NSObject or any Swift class that doesn't inherit from anything) but not when constraining the extension to a child class.

Upvotes: 1

Views: 608

Answers (2)

Kametrixom
Kametrixom

Reputation: 14983

I'm not entirely convinced, but this smells like a bug. Have a look at this example which doesn't compile:

protocol P {
    init(n: Int)
}

class A {}

class B : A {}

extension P where Self : B {
    func f() -> Self {
        return Self(n: 3) // Error
    }
}

But this compiles:

extension P where Self : A {
    func f() -> Self {
        return Self(n: 3)
    }
}

Probably you don't want a protocol for that anyways, since you even named it StringsViewController. You should probably subclass UIViewController:

class StringsViewController : UIViewController {
    convenience init(strings: [String]) {
        self.init()
    }
}

extension StringsViewController {
    func test() {
        let _ = StringsViewController(strings: [])
    }
}

Or if you really want a protocol you can do something like this:

protocol HasView {
    var view : UIView! { get }
}
protocol StringsInitable {
    init(strings: [String])
}

extension UIViewController : HasView {}

extension HasView where Self : StringsInitable {
    func test() {
        let n = Self(strings: [])
        print(n.view)
    }
}

Upvotes: 2

itskoBits
itskoBits

Reputation: 445

UIViewController doesn't have such an initialiser, because you haven't implemented the StringsViewController protocol. You would not be able to implement this protocol for UIViewController, because you cannot declare a designed initialiser into an extension. On the other hand you need a designated initialiser in order to conform to a init requirement of a protocol.

Upvotes: 0

Related Questions