我的许多 tableView 都需要一种方法,当最后一个单元格显示在屏幕上时加载更多数据。为了避免数百次实现相同的方法,我决定创建自己的 UITableView 基子类,它将在显示最后一个单元格时调用 tableView 委托(视图控制器)的方法,要求它加载更多数据,并且如果数据加载成功,将重新加载表视图。我认为这是相当合理的,特别是当我的应用程序中几乎每个表格视图都需要此功能时。
不幸的是,
tableView:willDisplayCell:forRowAtIndexPath:
是一个UITableViewDelegate方法。我非常确定,将 UITableView 子类设为 UITableViewDelegate 是错误的。所以,我需要创建一个 UITableViewController 基类。但如果我实现一个基本的 UITableViewController,我可能会想在子类中重写 tableView:willDisplayCell:forRowAtIndexPath:
。
此外,我的一些 tableView 嵌入在 ViewController 中,而不是 TableViewController 中(因为除了表 View 之外还有其他东西),所以这意味着我需要一个单独的 UITableViewController 和 UIViewController 子类。所以这只会让事情变得更加复杂。
那么如何使“在显示最后一个单元格时加载更多数据”功能可重用(遵循 MVC 指南)?
编辑:所以我想我已经知道如何开始了。我想要一个基本的 TableViewDelegateClass,例如BaseTableViewDelegate。然后,我想对其进行子类化,覆盖
tableView:willDisplayCell:forRowAtIndexPath:
,但调用 super.tableView:willDisplayCell:forRowAtIndexPath
。现在,我还有一个问题。我想让它重新加载数据。但我觉得在 tableView 委托中引用 tableView 是一个坏主意(可能是一个引用循环)。有没有好的协议解决方案?
EDIT3:我也在考虑另一种方法:
protocol MyTableViewDelegate: UITableViewDelegate {
func default_tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
func loadMoreData()
}
extension MyTableViewDelegate {
func default_tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
if(indexPath.section == tableView.numberOfSections - 1 && indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 )
{
self.loadMoreData()
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
self.default_tableView(tableView, willDisplay: cell, forRowAt: indexPath)
//do something else here that is not done in default_tableView
}
}
class MyView: UIView, MyTableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
self.default_tableView(tableView, willDisplay: cell, forRowAt: indexPath)
}
func loadMoreData()
{
loadMoreDataFromServer(){
tableView.reloadData()
}
}
}
但这看起来有点难看。
您可以为
UITableViewDelegate
创建扩展并在其中编写 tableView:willDisplayCell:forRowAtIndexPath:
的默认实现。然后你的子类的每个实例都会调用这个实现。
extension UITableViewDelegate {
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
// do what you need here, each ViewController that conforms to UITableViewDelegate will execute this implementation unless told otherwise
}
}
编辑: 另一种选择是为所有需要该行为的
ViewController
创建一个基础 ViewControllers
。在这种情况下,您不需要子类化 UITableView
。
您创建一个这样的类:
class BaseViewControllerForReloadingTables: UIViewController, UITableViewDelegate {
private var needToLoadMoreData: Bool = false
@IBOutlet var reloadingTableView: UITableView!
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if needToLoadMoreData {
loadMoreData()
}
}
private func loadMoreData() {
//load data
//if loading was successful
if reloadingTableView != nil {
reloadingTableView.reloadData()
}
}
}
然后每个需要向表加载更多数据的
ViewController
就继承这个类。例如:
class ReloadingTableViewController1: BaseViewControllerForReloadingTables {
}
和:
class ReloadingTableViewController2: BaseViewControllerForReloadingTables {
}
在这些子类中,您有
UITableView
,即 reloadingTableView
。当调用其委托函数时,将执行超类中的实现。这样,数据加载和表重新加载就可以在一个地方处理,但以适当的方式处理您的每个ViewControllers
。
当然,您可以向
BaseViewControllerForReloadingTables
类添加更多常用功能 - 取决于您的屏幕有多少相似的行为。
希望有帮助。