Changes in Swift 5 to inheritance?

We have a strange situation where behavior has changed from Swift 4 -> 5 and I can't figure out what is going wrong. We have our own open base table view controller class in a framework that conforms to UITableViewDatasource and UITableViewDelegate. In Swift 4 the subclasses could simply implement any of those delegate methods and they would work as expected. With Swift 5 and the latest Xcode this has all changed and any signature from those protocols that isn't explicitly written out in the base class are completely ignored, causing all kinds of strange bugs.


Our base class implementation looks something like this:


open class OsuTableViewController: OsuViewController, UITableViewDelegate, UITableViewDataSource {
    public let tableView = UITableView(frame: .zero, style: .grouped)

    public var tableSections = [OsuTableSection]()


    override open func viewDidLoad() {
        super.viewDidLoad()
        tableView.datasource = self
        tableView.delegate = self
    }


    open func numberOfSections(in tableView: UITableView) -> Int {
        return tableSections.count
    }

    open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch tableSections[section].tableSectionType {
        default:
            return tableSections[section].rows.count
        }
    }

    open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(OsuTableViewCell.self)
        return cell
    }
}



In Swift 4 any subclass then would be able to implement didSelectRowAtIndexPath or viewForHeaderInSection even without those declarations being explicitly stated in the base class.


class AboutYouCustomizeTableViewController: OsuTableViewController {
    // With Xcode 10.2 and Swift 5 this is never called. It worked for years prior.
    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }
}


With Swift 5 we find that the signatures in the subclasses are simply ignored unless we start writing out every single one in the base class. This is painful and sometimes leads to undesired behavior. Is this an intentional change or a bug? How do we get the old behavior back?

Answered by FishOSU in 356797022

After some more digging around it looks like this is a known bug with the Swift 5 compiler.


https://bugs.swift.org/browse/SR-10257


That's actually a relief! I'll implement the workaround as suggested and wait for it to get addressed in the next update.


Thanks for your prompt attention to this - you do great work and I always appreciate how quickly you hop in on these sorts of things!

I’m not sure what’s going on here. I distilled your example down to something standalone:

class BaseTableView: UIViewController, UITableViewDelegate, UITableViewDataSource {

    override func loadView() {
        let tableView = UITableView(frame: .zero, style: .plain)
        self.view = tableView
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.delegate = self
        tableView.dataSource = self
    }

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = ["Hello", "Cruel", "World!"][indexPath.row]
        return cell
    }
}

class MainViewController: BaseTableView {

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        NSLog("did select %d", indexPath.row)
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

and it works for me. Specifically, when I tap on one of the cells, it logs

2019-04-12 13:24:08.297746+0100 xxsi[68430:6039026] did select 2

I see a lot of access modifiers in your code. Are

OsuTableViewController
and
AboutYouCustomizeTableViewController
in different modules?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

What happens if you add override for


    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 
        return true 
    }
Accepted Answer

After some more digging around it looks like this is a known bug with the Swift 5 compiler.


https://bugs.swift.org/browse/SR-10257


That's actually a relief! I'll implement the workaround as suggested and wait for it to get addressed in the next update.


Thanks for your prompt attention to this - you do great work and I always appreciate how quickly you hop in on these sorts of things!

Changes in Swift 5 to inheritance?
 
 
Q