简体   繁体   English

Swift协议定义的初始化不适用于UIViewController

[英]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... 当对NSObject进行约束时,尝试在扩展中使用初始化程序。

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

...but not when constraint to UIViewController. ...但不限于UIViewController。 It then complains that the initializer should be labeled 'coder', referring to the mandatory initializer from NSCoding. 然后,它抱怨初始化程序应标记为“编码器”,这是指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? 即使是UIViewController子类,有没有办法使用协议中声明的初始化程序?

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. 当将扩展限制为基类(NSObject或任何不继承自任何东西的Swift类)时,这似乎是可行的,但当将扩展限制为子类时,则无效。

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 . 无论如何,您可能都不想要该协议,因为您甚至将其命名为StringsViewController You should probably subclass UIViewController : 您可能应该子类化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. UIViewController没有这样的初始化程序,因为您尚未实现StringsViewController协议。 You would not be able to implement this protocol for UIViewController, because you cannot declare a designed initialiser into an extension. 您将无法为UIViewController实现此协议,因为您无法在扩展中声明设计的初始化程序。 On the other hand you need a designated initialiser in order to conform to a init requirement of a protocol. 另一方面,您需要指定的初始化程序才能符合协议的初始化要求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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