使用默认行为

时间:2016-10-19 13:30:39

标签: ios iphone swift uitableview model-view-controller

当我在屏幕上显示最后一个单元格时,我的许多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()
        }   
    }
}

但这看起来有点难看。

1 个答案:

答案 0 :(得分:0)

您可以为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 {

}

在这些子类中,UITableViewreloadingTableView。调用其委托函数时,将执行超类中的实现。这样,数据加载和表格重新加载在一个地方处理,但以适当的方式处理每个ViewControllers

当然,您可以为BaseViewControllerForReloadingTables课程添加更多常用功能 - 取决于您的屏幕有多少相似的行为。

希望它有所帮助。