1

I have a tableView with cells that use inheritance. There is one common ancestor, and then there are several specific implementations. The common class does not override init(style:reuseIdentifier:) and it rather defines its own custom initializer. All the subclasses however do define this initializer, in which they call the custom one from the super class. Now in the tableView I register the subclasses for the reuse, and I am dequeuing subclasses for reuse. Yet I get following error when I try to dequeue any of the subclasses:

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

where milan.BotChatBaseCell is the superclass. Now milan.BotChatBaseCell is never registered to the tableView. Any idea why is this happening?

Code:

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")
    }
}

I have just tested it, it works on Swift 3.2, but not on Swift 4.

Milan Nosáľ
  • 17,130
  • 3
  • 42
  • 73
  • have had a look at this [answer](https://stackoverflow.com/a/24036440/4056108) – chirag90 Sep 11 '17 at 13:22
  • However you define `init(style:reuseIdentifier:)` in superclass still you need to implement in each subclass even though you are not using it and don't forgot to call super.init(style:) – Prashant Tukadiya Sep 11 '17 at 13:25
  • 1
    Please don't just talk _about_ your code. _Show_ it. Give us something we can copy and paste right into a project and see the problem. At the very least, show the relevant part of the common class! – matt Sep 11 '17 at 13:25
  • @milan-nosáľ : show your cellForRowAtIndexPath implementation then we will be able to help you – Sandeep Bhandari Sep 11 '17 at 13:29
  • edited the question – Milan Nosáľ Sep 11 '17 at 13:39

2 Answers2

3

The common class does not override init(style:reuseIdentifier:) and it rather defines its own custom initializer.

That's the problem. By making a new designated initializer, you have thrown away inheritance, so that BotChatBaseCell no longer inherits the designated initializer init(style:reuseIdentifier:). It must implement this.

One possible solution is to make your new initializer a convenience initializer and thus allow inheritance to keep working. Another possible solution is to add an override of init(style:reuseIdentifier:), even if it is trivial (i.e. it just calls super).

matt
  • 447,615
  • 74
  • 748
  • 977
  • thanks.. any explanation why the code works in Swift 3, but not Swift 4? – Milan Nosáľ Sep 11 '17 at 13:56
  • Who knows? Cocoa Touch is a black box: the code is hidden. You're asking me to speculate about what goes on inside it, or inside the minds of the people at Apple? That seems sort of pointless. Perhaps you were doing this wrong before and they added a check so that you get an exception when you do that, forcing you to do it right. But really, I don't know and I don't really care. Presumably it all has something to do with the fact that Cocoa is written in Objective-C, not Swift, and it's old, so the legacy code doesn't always follow Swift's initializer rules. – matt Sep 11 '17 at 14:01
1

You need to add initialiser in parent class and that should be override only in child class if it's written in parent class. I have fixed your code. Please check.

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")
    }
}
  • your code is not even compilable. Moreover, the question is already answered, matt already pointed out the correct approach to fixing it. – Milan Nosáľ Sep 11 '17 at 14:18
  • I have checked the code in my Xcode and it was crashing with your code. And i fixed by adding initialiser in base class. Check code now, it may issue while pasting the answer to stack overflow. I have my own libraries for abstraction which is useful in all projects. I helps you and you vote me down. Please check now and think again about voting. Thanks – Lakhwinder Singh Sep 11 '17 at 15:02