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?
}