Swift使用未实现的初始化器'init()'

3

第一部分

我正在使用NSExtensionPrincipalClass编写Today Widget扩展,而不是使用故事板。我实现了以下必需的初始化方法:

required init(coder aDecoder: NSCoder) {
    tableView = UITableView()
    cellIdentifier = "kCellIdentifier"

    super.init(coder: aDecoder)
}

然而,当我运行项目时,出现以下错误。
use of unimplemented initializer 'init()'

所以,通过在项目中加入这个额外的代码,可以解决问题,但在多个地方初始化变量似乎不太对。
override init() {
    tableView = UITableView()
    cellIdentifier = "kCellIdentifier"

    super.init()
}

第二部分

我已回答下面问题的第一部分,但我仍然不知道为什么以下解决方案不起作用?

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
    cellIdentifier = "kCell"
    tableView = UITableView()
    super.init(nibName: nil, bundle: nil)
}

根据Swift的文档,“如果您的子类提供了其超类指定初始化器的所有实现——通过根据规则1继承它们,或通过在其定义中提供自定义实现——那么它会自动继承超类方便初始化器。” 在UIViewController中,init(nibName:bundle:)是唯一的指定初始化器,那我为什么没有自动继承init()和init(coder:)呢?

Swift的初始化处理有点反直觉。在Obj-C中,所有的初始化器都被每个子类继承,无论它们在层次结构中有多远。在Swift中,初始化器只在特定情况下继承。你可能看到的是Obj-C调用一个在Obj-C中自动继承但在Swift中不会继承的初始化器。我自己也遇到过这种情况。最终,我回去重新阅读了Swift指南中的初始化器部分,大约读了半打次,直到弄明白为止。这就是我建议的方法。 :-) - Anna Dickinson
是的,Swift 中的 NSCoder 业务很混乱。我正在做和你一样的事情。如果你从另一个控制器初始化一个控制器,则不需要 aDecoder,但如果你从故事板初始化,则需要。混乱,我同意,但到目前为止我还没有找到解决方法。我甚至在这里问过:http://stackoverflow.com/questions/26394009/create-a-uiviewcontroller-extended-class-with-a-custom-initializer - Aggressor
1个回答

4

在重新阅读Swift的初始化器章节并查看UIViewController头文件后,我找到了第一个问题的解决方案。

required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override init() {
    cellIdentifier = "kCellIdentifier"
    tableView = UITableView()
    super.init(nibName: nil, bundle: nil)
}

这个解决方案的关键之一是 init(nibName:bundle:),这是一个指定的初始化方法,无论你是否使用storyboard,都必须调用它。
要点如下:
- 如果在声明变量时没有为其提供值,则会失去从超类继承的所有初始化器。这意味着您必须提供自己的 init 或重写超类初始化器并调用超类的适当指定初始化器。另外,您必须实现所有必需的初始化器。 - 在 UIViewController 中,默认情况下,convenience init 将使用 nil 作为参数自动调用 init(nibName:bundle:) 方法。因此,如果您没有继承默认的 init() 方法,则需要重写它并调用 init(nibName:bundle:)。

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