【问题标题】:Swift: Implementing Protocol Initializer in a ClassSwift:在类中实现协议初始化器
【发布时间】:2017-02-22 16:41:21
【问题描述】:

我试图理解为什么 Swift 强制使用一个符合协议的类,并且初始化器被标记为必需的。这实质上强制任何子类也实现该初始化程序。指定的超类初始化器肯定会被继承吗?

以下引述摘自 Swift 语言指南: https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID272

您可以在符合要求的情况下实现协议初始值设定项要求 类作为指定初始化器或便利初始化器。 在这两种情况下,您都必须使用 所需的修饰符:

class SomeClass: SomeProtocol {
    required init(someParameter: Int) {
        // initializer implementation goes here
    }
}

class SomeSubclass: SomeClass {
    required init(someParameter: Int) { // enforced to implement init again
        // initializer implementation goes here
    }
}

使用 required 修饰符可确保您提供显式 或继承所有初始化器要求的实现 符合类的子类,这样它们也符合 协议。

编辑: 我最初并没有提到我目前仅限于 Swift 2.1。这似乎是此版本中的编译器问题,并且在以后的版本中不会出现。

【问题讨论】:

    标签: swift inheritance swift-protocols


    【解决方案1】:

    指定的超类初始化器肯定会被继承吗?

    不,并非总是如此。如果子类定义了自己的指定初始化器,那么它不会自动继承超类的指定初始化器。考虑以下示例:

    class Foo {
        init() {}
    }
    
    class Bar : Foo {
    
        var str: String
    
        init(str: String) {
            self.str = str
        }
    }
    
    let b = Bar() // illegal – what value would the 'str' property have?
    

    由于Bar 定义了自己的init(str:) 指定初始化程序,它不会自动继承Foo 的指定初始化程序init()。这可以防止在子类声明自己的存储属性的情况下进行不安全的初始化。

    init() 标记为required 强制 Bar 有一个init(),可以通过提供自己的实现来实现:

    class Foo {
        required init() {}
    }
    
    class Bar : Foo {
    
        var str: String
    
        init(str: String) {
            self.str = str
        }
    
        // implement required init(), as Bar defines its own designated initialiser.
        required init() {
            self.str = "foo" // now str is correctly initialised when calling init()
        }
    }
    
    let b = Bar() // now legal
    

    或者通过继承Foo的实现(当Bar没有定义自己的指定初始化器时):

    class Foo {
        required init() {}
    }
    
    class Bar : Foo {
        // inherits init() from Foo, as Bar doesn't define its own designed initialisers.
    }
    
    let b = Bar() // legal
    

    【讨论】:

    • 这对于将其标记为必需的推理很有意义。我想让我失望的是,在 Swift 2.1 中,即使子类没有指定的初始化程序,编译器也会强制您实现超类初始化程序。
    • 将此标记为已接受,因为它解释了我的问题“肯定会继承指定的超类初始化程序吗?”。我遇到的原始问题是由于 Swift 2.1 的限制。
    【解决方案2】:

    您不必在子类中实现初始化程序。考虑这个例子,它编译得很好:

    protocol SomeProtocol {
        init(someParameter: Int)
    }
    
    
    class SomeClass: SomeProtocol {
        required init(someParameter: Int) {
            // initializer implementation goes here
            print(someParameter)
        }
    }
    
    
    class SomeSubclass: SomeClass {
        // Notice that no inits are implemented here
    }
    
    _ = SomeClass(someParameter: 123)
    _ = SomeSubclass(someParameter: 456)
    

    【讨论】:

    • 我应该提到我目前仅限于 Swift 2.1,因此可能是该版本中的一个错误。你用什么版本编译的?
    • Swift 3。Swift 2 已弃用。
    • 感谢您验证版本。我知道它已被弃用,但由于我无法控制的情况,我目前仅限于使用它。很高兴知道它已在以后的版本中得到解决。
    猜你喜欢
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    相关资源
    最近更新 更多