简体   繁体   中英

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.

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)
    }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM