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?
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements.
In Swift, protocols contain multiple abstract members. Classes, structs and enums can conform to multiple protocols and the conformance relationship can be established retroactively.
Protocol is used to specify particular class type property or instance property. It just specifies the type or instance property alone rather than specifying whether it is a stored or computed property. Also, it is used to specify whether the property is 'gettable' or 'settable'.
To create a protocol, use the protocol keyword followed by the name you want and defined by the curly braces. Protocols can be of 2 types: read-only/read-write. Read-only means you can only get the variable, but you cannot set it. Read-write means you can both set and get properties.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With