Calling super on optional protocol method, when the parent class conforms to the protocol

Take this UITableViewController subclass:

final class MyTableViewController: UITableViewController {

    override func tableView(_ tableView: UITableView,
                            willDisplay cell: UITableViewCell,
                            forRowAt indexPath: IndexPath) {
        super.tableView(tableView, willDisplay: cell, forRowAt: indexPath)
    }

The above code crashes with the well known unrecognized error message, because the parent class didn't implement the method. The UITableViewDataSource method in discussion is optional, and it makes sense for UITableViewController not to have implemented it.

However, I think we have a compiler issue here: the method is not exposed as optional when attempting to call it via super, so there's one compile-time check that we miss. This might be caused by the fact that only protocols have support for optional methods, so I think this is a corner-case of Swift.

Also, being forced to write override, even if the parent class doesn't implement the method, can lead to confusion, since developers might expect for the base parent to already have it implemented.

In order to avoid runtime crashes, the developer needs to be diligent and add respondsTo checks:

if super.responds(to: #selector(tableView(_:willDisplay:forRowAt:))) {
    super.tableView(tableView, willDisplay: cell, forRowAt: indexPath)
}

, however this adds more boilerplate, and it's a runtime check only.

Also, the documentation for UITableViewController is not very helpful in respect to this, as it doesn't mention which methods from the datasource/delegate protocols are implemented, so one can easily fall into this trap of calling super on a non-existing method.

Is this worth fixing within the compiler? Or should Apple just update the documentation for UITableViewController (and other classes that exhibit similar behaviour, like the collection view controller) to reflect this quirk?

2 Likes

BOTH!

Thank you for bringing this up.

Also please let me get on the soapbox, and say a few words.

Apple documentation is so lacking these days, only because of the obsession with auto generated stuff from the source code. Proper, written programming guides are becoming endangered species. I hate watching the bloody videos they provide these days - trying to learn from them is not only waste of time but also literally waste of energy.

1 Like

The docs should be better. The videos are good and yet could be better. But you're missing the important realization—the generation who says what you said is an endangered species as well, and their energy would be better spent not yelling at clouds. Be more respectful while you're still alive!

2 Likes

I also find it strange that override keyword is needed in this case, for normal protocol requirements we don't write override (1)

As you mentioned this is a corner case for swift, as it doesn't have optional protocol requirements, other than those imported from Obj-C.

(1) On a separate note, I believe having some keyword like "implements" to denote protocol requirements would be useful.

The parent class (UITableViewController) conforms to the protocol, so the compiler assumes it implemented the method, thus the necessity to add the override keyword in the child class.

Yes, the problem seems to reproduce only for Objective-C parent classes, tried to replicate the same setup with a Swift class, and the compiler didn't let, nor force me, to add the override keyword, as it was able to detect that the base class didn't implement the optional method.