【问题标题】:`tableView.dequeueReusableCell(withIdentifier:for:)` calls initializer from the parent class`tableView.dequeueReusableCell(withIdentifier:for:)` 从父类调用初始化程序
【发布时间】:2017-09-11 13:21:08
【问题描述】:

我有一个tableView,其中包含使用继承的单元格。有一个共同的祖先,然后有几个具体的实现。公共类不会覆盖init(style:reuseIdentifier:),而是定义了自己的自定义初始化程序。然而,所有的子类都定义了这个初始化器,它们从超类中调用自定义的初始化器。现在在tableView 中,我注册了子类以供重用,并且我正在使子类出列以供重用。然而,当我尝试使任何子类出队时出现以下错误:

fatal error: use of unimplemented initializer 'init(style:reuseIdentifier:)' for class 'milan.BotChatBaseCell'

其中milan.BotChatBaseCell 是超类。现在milan.BotChatBaseCell 从未注册到tableView。知道为什么会这样吗?

代码:

import UIKit

class ViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(ExampleBotChatCell.self, forCellReuseIdentifier: "ExampleBotChatCell")
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ExampleBotChatCell", for: indexPath) as! ExampleBotChatCell
        return cell
    }
}

class BotChatBaseCell: UITableViewCell {
    init(style: UITableViewCellStyle, reuseIdentifier: String?, customString: String) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        print(">>>> nice \(customString)")
    }

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

class ExampleBotChatCell: BotChatBaseCell {

    init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier, customString: "Example")
    }

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

我刚刚测试过,它适用于 Swift 3.2,但不适用于 Swift 4。

【问题讨论】:

  • 看过这个answer
  • 然而你在超类中定义init(style:reuseIdentifier:) 仍然需要在每个子类中实现,即使你没有使用它并且不要忘记调用 super.init(style:)
  • 请不要只谈论您的代码。 显示它。给我们一些我们可以复制并粘贴到项目中并查看问题的东西。最起码,展示公共类的相关部分!
  • @milan-nosáľ : 展示您的 cellForRowAtIndexPath 实现,然后我们将能够为您提供帮助
  • 编辑了问题

标签: ios swift uitableview


【解决方案1】:

通用类不会覆盖 init(style:reuseIdentifier:) 而是定义自己的自定义初始化器。

这就是问题所在。通过创建一个新的指定初始化程序,您已经抛弃了继承,因此BotChatBaseCell 不再继承指定初始化程序init(style:reuseIdentifier:)。它必须实现这一点。

一种可能的解决方案是使您的新初始化程序成为便利初始化程序,从而允许继承继续工作。另一种可能的解决方案是添加对init(style:reuseIdentifier:) 的覆盖,即使它是微不足道的(即它只是调用super)。

【讨论】:

  • 谢谢.. 为什么代码在 Swift 3 中有效,但在 Swift 4 中无效?
  • 谁知道? Cocoa Touch 是一个黑盒子:代码是隐藏的。你是在让我推测它内部发生的事情,或者 Apple 员工的想法?这似乎有点毫无意义。也许您之前做错了,他们添加了一个检查,以便您在执行此操作时遇到异常,从而迫使您正确执行。但说真的,我不知道,我也不在乎。大概这一切都与 Cocoa 是用 Objective-C 而不是 Swift 编写的这一事实有关,而且它很旧,所以遗留代码并不总是遵循 Swift 的初始化规则。
【解决方案2】:

您需要在父类中添加初始化程序,如果它是在父类中编写的,则只能在子类中覆盖。 我已经修复了你的代码。请检查。

import UIKit

class ViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(ExampleBotChatCell.self, forCellReuseIdentifier: "ExampleBotChatCell")
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ExampleBotChatCell", for: indexPath) as! ExampleBotChatCell
        return cell
    }
}


class BotChatBaseCell: UITableViewCell {

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    init(style: UITableViewCellStyle, reuseIdentifier: String?, customString: String) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

    }

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

// example subclass:
class ExampleBotChatCell: BotChatBaseCell {

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier, customString: "Example")
    }

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

【讨论】:

  • 您的代码甚至无法编译。此外,问题已经得到解答,马特已经指出了解决问题的正确方法。
  • 我检查了我的 Xcode 中的代码,它与您的代码一起崩溃。我通过在基类中添加初始化程序来修复。现在检查代码,在粘贴堆栈溢出的答案时可能会出现问题。我有自己的抽象库,在所有项目中都很有用。我帮助你,你投票否决我。请现在检查并重新考虑投票。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 2016-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多