【问题标题】:Multiple tableviews using a shared datasource but varying number of rows使用共享数据源但行数不同的多个表视图
【发布时间】:2021-10-29 01:04:26
【问题描述】:

我的应用中有几个表视图,它们使用一个名为 TaskListDataSource 类的数据源实例,该类符合 UITableViewDataSource

class TaskListDataSource: NSObject {
    typealias TaskCompletedAction = () -> Void
    
    private var tasks: [Task] = SampleData.tasks
    private var taskCompletedAction: TaskCompletedAction?
    
    init(taskCompletedAction: @escaping TaskCompletedAction) {
        self.taskCompletedAction = taskCompletedAction
        super.init()
    }
}

extension TaskListDataSource: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tasks.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "taskCell", for: indexPath) as? TaskCell else {
            fatalError("Unable to dequeue TaskCell")
        }
        cell.configure(task: tasks[indexPath.row]) {
            self.tasks[indexPath.row].completed.toggle()
            self.taskCompletedAction?()
        }
        return cell
    }
}

我通过依赖注入传入实例并像这样设置 tableview 数据源。我为所有使用此数据源对象的视图控制器执行此操作。

var taskListDataSource: TaskListDataSource
    
init?(coder: NSCoder, taskListDataSource: TaskListDataSource) {
    self.taskListDataSource = taskListDataSource
    super.init(coder: coder)
}
    
required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(UINib(nibName: "TaskCell", bundle: nil), forCellReuseIdentifier: "taskCell")
    tableView.dataSource = taskListDataSource
}

但是我想实现一种方法,以便在其中一个 UITableViewController 上将行数限制为 3 行。目前因为下面的代码 sn-p 它总是只显示任务数组中的任务总数。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return tasks.count
}

在每个 tableview 上,它显示了任务的总数,但我想要一种方法,我可以以某种方式保持 cellForRowAt 函数的可重用性,同时使 numberOfRows 函数动态化。

【问题讨论】:

  • 将属性添加到TaskListDataSource,以了解您是否应该“应限制为 3”(如果任务较少,则应限制为更少)并检查 numberOfRowsInSection 中的值?
  • @Larme 因为我只有这个TaskListDataSource 的一个实例,所以每次用户查看一个新的tableview 时都需要更新这个属性。所以我必须不断地设置属性并重新加载viewDidAppear中的tableview。还有比这更清洁的方法吗?
  • 最好的办法可能是分开你的班级。一部分负责保存数据(例如 TaskListDataStore)并且是单个实例,另一部分负责显示数据(TaskListDataSource)。然后,您可以从 TaskListDataSource 为每个控制器创建一个实例。
  • @Johannes Starke 我非常喜欢这个。它适用于我创建的通用模型存储类。所以我会将该存储注入到每个控制器中,并通过 TaskListDataSource 对象的每个初始化程序将其提供给它。但是,当进行更改时,我将如何使所有 tableview UI 保持同步? (例如,指示是否完成的任务复选框)
  • 在大多数情况下,如果您在 viewWillAppear 中重新加载数据就足够了,对吧?否则,您还可以将经典委托(或回调)添加到您的商店,以便 ViewController 可以注册更改。

标签: ios swift uitableview


【解决方案1】:

你可以添加一个字典来保存每个tableview的限制

    ...
    private maxRows: [String: Int?] = [:]
    ...

添加处理绑定数据源的函数

    ...
    func add(_ tableView: UITableView, maxRows: Int? = nil) {
        if let id = tableView.id {
            self.maxRows[id] = maxRows
        }
        tableView.datasource = self
    }
    ...

那么数据源函数numberOfRowsInSection就变成了

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let id = tableView.id {
              return maxRows[id] ?? tasks.count
        }
        return tasks.count
}

并设置tableview数据源

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(UINib(nibName: "TaskCell", bundle: nil), forCellReuseIdentifier: "taskCell")
    taskListDataSource.add(tableView, maxRow: 3) 
}

tableView.id 可以是你想要的任何东西。例如:你继承 UITableView 并添加一个属性

class UITableViewWithID: UITableView {
    var id: String?
}

【讨论】:

  • 我决定使用您的识别概念,并将以下内容添加到 numberOfRows 函数return tableView.accessibilityIdentifier == "ReviewViewController" ? tasks.count : 3
猜你喜欢
  • 2014-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多