maniek
maniek

Reputation: 7307

swift inherited protocol method override

I was hoping this would work:

protocol Foo : UITableViewDelegate{
}

extension Foo{
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        print("ROW:\(indexPath.row)")
    }
}

class MyVC : UITableViewController, Foo{
   //...
}

No luck though, the method does not get called. Am I missing something, or is this genuinely not possible?

Also, there is no compiler warning/error, the method is just not being called, which some may consider a bug.

Upvotes: 1

Views: 462

Answers (1)

hnh
hnh

Reputation: 14795

I think this is because your are inheriting from UITableViewController which already implements UITableViewDelegate.

You can easily test this:

class MyVC: UITableViewController {
  func tableView(tableView tv: UITableView, 
                 didSelectRowAtIndexPath ip: NSIndexPath) {}
}

This will result in

error: overriding declaration requires an 'override' keyword

The compiler assumes the method is already implemented in the direct inheritance chain. Hence your default method from the protocol won't be picked.

Having said that, the variant below does not work either. Adding @objc to the protocol makes my swiftc segfault ...:

import UIKit

protocol Foo : UITableViewDelegate {
  func tableView(tableView: UITableView, didSelectRowAtIndexPath: NSIndexPath)
}

extension Foo {

  func tableView(tableView: UITableView,
                 didSelectRowAtIndexPath _: NSIndexPath)
  {
    print("abcXXX")
  }

}

class ViewController: UIViewController, UITableViewDataSource, Foo {

  override func loadView() {
    self.view = UITableView(frame: CGRect())
  }

  var tableView : UITableView { return self.view as! UITableView }

  override func viewDidLoad() {
    super.viewDidLoad()

    self.tableView.delegate   = self
    self.tableView.dataSource = self
    self.tableView.registerClass(UITableViewCell.self,
                                 forCellReuseIdentifier: "MyCell1")
  }

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

  func tableView(tableView: UITableView, cellForRowAtIndexPath ip: NSIndexPath)
        -> UITableViewCell
  {
    let cell = tableView
                 .dequeueReusableCellWithIdentifier("MyCell1", forIndexPath: ip)
    cell.textLabel?.text = "p[\(ip.row)]"
    return cell
  }
}

Hence I assume my answer is only 50% right. Presumably protocol extensions only work in static binding contexts, which excludes ObjC protocols?

Update: This seems to be the proper answer: Protocol-Oriented Programming with UIKit. The essence:

What we CAN'T do: Provide default implementations for Objective-C protocols.

Upvotes: 1

Related Questions