创建具有默认行为的更可重用的 UITableView 子类

问题描述 投票:0回答:1

我的许多 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()
        }   
    }
}

但这看起来有点难看。

ios iphone swift uitableview model-view-controller
1个回答
1
投票

您可以为

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
类添加更多常用功能 - 取决于您的屏幕有多少相似的行为。

希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.