You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 08:37:44