调用协议扩展初始化器

Calling a protocol extension initializer

我正在尝试构建一组共享通用初始化代码的 classes。除了继承,我认为协议是可行的方法。虽然协议和协议扩展适用于实例和静态方法,但我在使用初始化程序时遇到了一些麻烦。

假设我们有这个协议:

protocol CloudServiceWrapper {

    static var isConfigured: Bool { get }

    init()

    func initialize()

}

现在假设我们要在协议扩展中为 isConfiguredinit() 添加默认实现:

extension CloudServiceWrapper {

    static var isConfigured: Bool {
        get {
            return true
        }
    }

    init() {
        print("Initializing generic CloudServiceWrapper")
        self.init()
        if Self.isConfigured {
            initialize()
        }

    }

}

最后,让我们class实现这个协议并尝试从它的默认实现中获益:

class OneDriveWrapper: CloudServiceWrapper {

    required init() {
        // CloudServiceWrapper() // error: protocol type 'CloudServiceWrapper' cannot be instantiated
        // self = CloudServiceWrapper.init() // error: cannot assign to value: 'self' is immutable
        // super.init() // error: 'super' members cannot be referenced in a root class
        // (self as CloudServiceWrapper).init() // error: static member 'init' cannot be used on instance of type 'CloudServiceWrapper'
        print("Initializing OneDriveWrapper")
    }

    func initialize() {
        print("Done")
    }

}

在尝试构建 OneDriveWrapper class 的新实例时,我根本找不到同时调用 class 初始化程序和默认协议实现的方法。并且不可能在 OneDriveWrapper class 中省略 init(),因为根据协议定义它是必需的,并且似乎不考虑 "implemented" 协议扩展。

事实上,更广泛地说,我找不到任何方法来显式调用协议扩展的初始化程序,即使我知道实例方法是可能的。

我做错了什么?您知道将 class' 初始化器和协议扩展的初始化器结合起来的任何方法吗?我应该回退到 class 继承而不是协议和扩展吗?

谢谢!


这个回答并没有指出OP的核心问题。留在这里只是为了 记录.


你做的完全错了。协议不是超类。

协议的默认实现只是当您不实现协议所需方法时使用的默认值。您不能以任何方式直接调用协议的默认实现。

协议不是超类的简单替换。根据协议改变你的思维方式。

尽管我知道实例方法是可能的。

你误会了什么。你不能调用协议的默认实现,即使它是一个方法。

protocol 中的 initrequired,因此必须显式实现,即不能使用默认实现。

至于“显式调用协议扩展的初始化程序”,您不能实例化协议类型。

我建议为此使用继承。

是一个类似的问题。

尽管协议提供了默认实现,为什么 class 仍需要初始化?答案是它不提供默认实现,而只是另一个初始化,这需要 class' init() 这里存在。

Since your protocol can't be certain to cover all members of the class that uses it, any initializer you declare in your protocol will need to delegate initialization of the "unknown" members of the class to another initializer provided by the class itself.

然而,您的协议 init 可能被 class' init() 隐藏,因此您将无法使用它。也许向 class initializer/the 协议所需的初始值设定项添加一个参数,或者向协议扩展 ìnit() 添加一个参数。如果 protocol-extension init 没有被 class 隐藏,你将能够使用它来初始化 class.

init 是必需的,因为 class 可以被子classed 并且初始化程序不一定是继承的,请参阅 inheritance doc and initialization doc under Initializer Inheritance and Overriding。如果不需要 init 子 class 将不再遵守协议,这是不可取的,因此协议中的 init 集仅由所需的初始化程序填充。

注意:在 required init() 中你试图调用另一个初始化器,但我认为除了初始化父级之外这是不可能的,因为 required init() 是一个指定的初始化器,不能链接在同一个 class,只有便利初始化器可以链接在同一个 class.

您可以将协议扩展 ìnit 视为便利初始化程序,因为 init 需要调用另一个初始化程序,就像每个其他便利初始化程序对 self.init(...) 所做的那样。