多UITableView共享TaskListDataSource时动态控制显示行数的技术问询
解决多TableView共用数据源时的行数动态适配问题
要实现单个TableView限制显示行数、同时保留数据源复用性的需求,我们可以给TaskListDataSource添加TableView专属配置的能力,让它能根据不同的TableView返回对应的行数。下面是具体的实现方案:
第一步:改造TaskListDataSource类
我们给数据源添加一个存储结构,用来记录每个TableView对应的行数限制,同时提供设置限制的方法,并修改numberOfRowsInSection方法做动态适配:
class TaskListDataSource: NSObject { typealias TaskCompletedAction = () -> Void private var tasks: [Task] = SampleData.tasks private var taskCompletedAction: TaskCompletedAction? // 用弱引用包装器存储TableView,避免内存泄漏 private var tableViewRowLimits: [Weak<UITableView>: Int?] = [:] init(taskCompletedAction: @escaping TaskCompletedAction) { self.taskCompletedAction = taskCompletedAction super.init() } // 给指定TableView设置行数限制,传nil则取消限制(显示全部任务) func setRowLimit(_ limit: Int?, for tableView: UITableView) { // 先清理已释放的TableView对应的无效配置 tableViewRowLimits = tableViewRowLimits.filter { $0.key.value != nil } let weakTableView = Weak(value: tableView) tableViewRowLimits[weakTableView] = limit } } // 自定义弱引用包装器,避免字典强持有TableView导致内存泄漏 class Weak<T: AnyObject> { weak var value: T? init(value: T) { self.value = value } } extension TaskListDataSource: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // 查找当前TableView对应的行数限制 let rowLimit = tableViewRowLimits.first { entry in entry.key.value == tableView }?.value ?? nil guard let limit = rowLimit else { // 无限制时返回全部任务数 return tasks.count } // 取任务总数和限制值的较小值,避免任务不足时显示错误行数 return min(tasks.count, limit) } 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 } }
第二步:在目标ViewController中设置行数限制
在需要只显示3行的那个UITableViewController里,添加一行配置代码即可:
override func viewDidLoad() { super.viewDidLoad() tableView.register(UINib(nibName: "TaskCell", bundle: nil), forCellReuseIdentifier: "taskCell") tableView.dataSource = taskListDataSource // 设置当前TableView最多显示3行 taskListDataSource.setRowLimit(3, for: tableView) }
其他不需要限制行数的ViewController不需要调用setRowLimit方法,会默认显示全部任务。
方案优势
- 完全保留了
cellForRowAt的复用逻辑,所有TableView仍然共用同一套单元格配置逻辑 - 通过专属配置实现了不同TableView的差异化需求,扩展性强(后续要给其他TableView设置不同限制,只需调用
setRowLimit即可) - 用弱引用包装器避免了内存泄漏问题,保证了数据源的内存安全
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

