Reputation: 2518
Consider the following code inside of a Module that is included via Cocoapods (I'm using Eureka
, but the problem should not be related to that):
open class FormViewController : UIViewController {
}
extension FormViewController : UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// some default implementation
}
/// some other UITableViewDelegate methods follow, but _NOT_ willDisplayCell
}
I am trying to subclass FormViewController
and add an implementation for tableView(_:willDisplay:forRowAt:)
(which is an optional method from UITableViewDelegate
). This method has no implementation in the origin FormViewController
:
import UIKit
import Eureka
class MyViewController: FormViewController {
override func viewDidLoad() {
let tableView = UITableView(frame: self.view.bounds, style: .grouped)
tableView.delegate = self
tableView.dataSource = self
self.tableView = tableView
self.view.addSubview(self.tableView!)
super.viewDidLoad()
form = Form()
let section = Section()
section.append(EmailRow(){
$0.tag = "email"
$0.title = "Email"
})
form += [section]
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print("NOT CALLED")
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("will be called")
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("GETS CALLED")
return super.tableView(tableView, cellForRowAt: indexPath)
}
}
/// somewhere else:
self.navigationController?.pushViewController(MyViewController(), animated: true)
With this setup, my overriden version of tableView(_:cellForRowAt:)
will be called (meaning that tableView.delegate
is set up properly). tableView(_:willDisplay:forRowAt:)
will not be called. As soon as I add a blank implementation in Eureka, I'm able to override the method.
Question: Why is Swift not using the method without a default implementation in the superclass?
Upvotes: 9
Views: 815
Reputation: 759
May be the problem is in controller instance declaration.
let myController: MyFormViewController = MyFormViewController()
tableView.delegate = myController
In this case everything should work correctly. But in another case
let myController: FormViewController = MyFormViewController()
tableView.delegate = myController
tableView(_:willDisplay:forRowAt:)
will not been executed.
Upvotes: -1
Reputation: 12334
I've noticed this problem myself, and it seems like a bug to me. You have two options.
First, you can implement the delegate method inside your extension and override it in your subclass. this will ensure the method is called.
extension FormViewController : UITableViewDelegate {
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// you can leave the implementation blank if you want
}
}
class MyViewController: FormViewController {
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print("CALLED!!")
}
}
Second, you can declare the method using the pre-Swift 3 notation and it will work. This part also feels like a bug to me (or all part of the same bug). I wouldn't recommend this option as it is likely to change in future Swift or Xcode versions and generally feels hacky.
extension FormViewController : UITableViewDelegate {
// no willDisplayCell method
}
class MyViewController: FormViewController {
func tableView(_ tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
print("CALLED!!")
}
}
EDIT: The fact that OP put the UITableViewDelegate
methods in an extension isn't causing the problem. The problem exists even if the class itself decalres the delegate.
Upvotes: 3
Reputation: 166
In my understanding extensions defined on a superclass don't work on the level of a child class if this is what you mean. You can implement a method however that you call from the child class to the super class to perform some default kind of behaviour specified in the class' extension.
Upvotes: 0