在子类内部实现协议方法

Ale*_*lex 8 uitableview ios swift

考虑通过Cocoapods包含的模块中的以下代码(我正在使用Eureka,但问题不应与此相关):

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
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试子类化FormViewController并添加一个实现tableView(_:willDisplay:forRowAt:)(这是一个可选方法UITableViewDelegate).此方法在原点中没有实现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)
Run Code Online (Sandbox Code Playgroud)

使用此设置,tableView(_:cellForRowAt:)将调用我的覆盖版本(意味着tableView.delegate正确设置).tableView(_:willDisplay:forRowAt:)不会被叫.只要我在Eureka中添加一个空白实现,我就可以覆盖该方法.

问题:为什么Swift在超类中没有默认实现时不使用该方法?

kei*_*ter 3

我自己也注意到了这个问题,对我来说这似乎是一个错误。你有两个选择。

首先,您可以在扩展中实现委托方法并在子类中重写它。这将确保调用该方法。

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!!")
    }
}
Run Code Online (Sandbox Code Playgroud)

其次,您可以使用 Swift 3 之前的表示法来声明该方法,它将起作用。这部分对我来说也感觉像是一个错误(或同一错误的所有部分)。我不推荐这个选项,因为它可能会在未来的 Swift 或 Xcode 版本中发生变化,并且通常感觉很hacky。

extension FormViewController : UITableViewDelegate {    
    // no willDisplayCell method
}

class MyViewController: FormViewController {
    func tableView(_ tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        print("CALLED!!")
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:OP 将方法放入扩展中的事实UITableViewDelegate并不会导致问题。即使类本身声明了委托,问题仍然存在。