苦恼理解Swift 3中可失败初始化器与不可失败初始化器的重写

5

我正在尝试学习Swift中覆盖可失败初始化器的概念,并遇到了以下语句:

将初始化委托给超类的唯一方法是强制解包可失败的超类初始化器的结果。

教科书没有提供任何代码来真正解释它的含义。请问有人能够友好地向我解释一下吗?最好附带一个代码示例!


你最好使用标题“覆盖可失败的初始化器”。 - CouchDeveloper
1个回答

7

我必须承认,"重写可失败初始化程序"这一部分很令人困惑。

下面的示例应该可以澄清这种情况:

假设您有一个带有可失败初始化程序的基类:

class Base {
    let name: String

    init?(name: String) {
        guard !name.isEmpty else {
            return nil
        }
        self.name = name
    }
}

请注意,失败的初始化器会返回一个Optional。
在这里,初始化器要求您传递一个非空字符串,否则初始化器将“失败”,即返回一个值为nil(分别为.None)的可选项。
现在,让我们定义一个从Base派生的类。 在第一个版本中,这将无法编译!
class Derived: Base {
    let age: Int

    init(name: String, age: Int) {
        self.age = age
        super.init(name: name) //<- error 
    }
}

编译器会报以下错误:
error: a non-failable initializer cannot chain to failable initializer 'init(name:)' written with 'init?'
        super.init(name: name)
              ^

这里的问题在于,子类的非可失败初始化器委托给了基类的可失败初始化器。

我们有两个选项来解决这个问题:

1. 强制解包可失败初始化器:

class Derived: Base {
    let age: Int

    init(name: String, age: Int) {
        self.age = age
        super.init(name: name)!   // <- force unwrap 
    }
}

这种解决方案的注意事项是,如果你将空的name传递给子类初始化器,例如:
let derived = Derived(name: "", age: 12)

在尝试从基类初始化程序中强制解包可选项时,会导致致命错误。
fatal error: unexpectedly found nil while unwrapping an Optional value

2. 将子类的初始化器也变成可失败的:

class Derived: Base {
    let age: Int

    init?(name: String, age: Int) {  // use failable initialiser
        self.age = age
        super.init(name: name)  // <- propagate the failure with init?
    }
}

这个解决方案只是将基类初始化程序的nil结果传播给调用者,这使得调用者负责适当地处理可选项。

非常详细的解释。比我想象中的要好得多。非常感谢! - user5849987

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接