Home > OS >  Multiple tableviews using a shared datasource but varying number of rows
Multiple tableviews using a shared datasource but varying number of rows

Time:09-17

I have a couple of tableviews in my app that use one instance of a datasource called TaskListDataSource class that conforms to 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
    }
}

I pass in the instance via dependency injection and set the tableview datasource like so. I do this for all my view controllers that use this datasource object.

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
}

however I would like to implement a way so that on one of the UITableViewControllers the number of rows is limited to 3 rows. At the moment because of following code snippet it will always just display the total amount of tasks in the tasks array.

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

On each tableview it shows the total amount of tasks but I want a way in which I can somehow keep the reusability of the cellForRowAt function but make the numberOfRows function dynamic.

CodePudding user response:

You could add a dictionary to save the limit of each tableview

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

add a function to handle the binding datasource

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

then the datasoure function numberOfRowsInSection become

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

and set the tableview datasource like

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

tableView.id could be whatever you want. ex: you subclass UITableView and add a property

class UITableViewWithID: UITableView {
    var id: String?
}
  • Related