iOS开发:双层TableView交互场景下的数据流转实现方案咨询
实现ViewController间数据流转的完整方案
Hey there! Welcome to the group, and awesome plan for your app. Let’s walk through the data flow logic step by step—this is a super common pattern in iOS development, so I’ll use Swift code examples to make it concrete.
1. 先定义统一的数据模型
首先,我们需要一个共享的数据结构,让两个控制器都能操作相同类型的数据。比如定义一个简单的ListItem结构体:
struct ListItem: Identifiable { let id = UUID() var title: String }
用Identifiable是为了方便UITableView的数据源处理,不用自己写cellForRowAt里的ID逻辑。
2. 主控制器(MainTableViewController)的配置
主控制器负责展示初始数据,以及接收从详情页返回的新数据并更新列表。
核心逻辑:
- 持有数据源数组
- 实现UITableView代理方法展示数据
- 点击单元格时,把当前数据传递给详情页,并设置闭包接收返回的新数据
class MainTableVC: UITableViewController { // 主数据源 private var items: [ListItem] = [ ListItem(title: "初始条目1"), ListItem(title: "初始条目2") ] override func viewDidLoad() { super.viewDidLoad() title = "主列表" tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") } // MARK: - UITableView DataSource override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = items[indexPath.row].title return cell } // MARK: - 跳转至详情页 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // 创建详情页控制器 let detailVC = DetailVC() // 传递当前选中的数据(如果需要详情页编辑现有数据的话) detailVC.currentItems = items // 设置闭包,用于接收详情页新增的数据 detailVC.onItemAdded = { [weak self] newItem in guard let self = self else { return } // 把新数据添加到主数据源 self.items.append(newItem) // 刷新表格 self.tableView.reloadData() } // 跳转(如果用导航控制器的话) navigationController?.pushViewController(detailVC, animated: true) } }
3. 详情控制器(DetailVC)的实现
详情页需要展示传入的数据,同时处理“添加按钮”的逻辑,并把新数据回传给主控制器。
核心逻辑:
- 接收主控制器传递的数据源
- 自己的UITableView展示这些数据
- 添加按钮触发创建新条目的逻辑,通过闭包回传数据
class DetailVC: UIViewController { // 接收从主控制器传来的数据 var currentItems: [ListItem] = [] // 定义闭包,用于回传新数据 var onItemAdded: ((ListItem) -> Void)? private lazy var tableView: UITableView = { let tv = UITableView() tv.translatesAutoresizingMaskIntoConstraints = false tv.register(UITableViewCell.self, forCellReuseIdentifier: "DetailCell") return tv }() private lazy var addButton: UIButton = { let btn = UIButton(type: .system) btn.translatesAutoresizingMaskIntoConstraints = false btn.setTitle("添加新条目", for: .normal) btn.addTarget(self, action: #selector(addButtonTapped), for: .touchUpInside) return btn }() override func viewDidLoad() { super.viewDidLoad() title = "详情列表" view.backgroundColor = .white // 设置子视图 setupSubviews() // 绑定tableView代理 tableView.dataSource = self } private func setupSubviews() { view.addSubview(tableView) view.addSubview(addButton) NSLayoutConstraint.activate([ addButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16), addButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), tableView.topAnchor.constraint(equalTo: addButton.bottomAnchor, constant: 16), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) } @objc private func addButtonTapped() { // 这里可以弹出输入框让用户输入内容,示例直接创建一个新条目 let newItem = ListItem(title: "新条目 \(currentItems.count + 1)") // 通过闭包把新数据回传给主控制器 onItemAdded?(newItem) // 同时更新详情页的表格 currentItems.append(newItem) tableView.reloadData() } } // MARK: - UITableView DataSource extension DetailVC: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return currentItems.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "DetailCell", for: indexPath) cell.textLabel?.text = currentItems[indexPath.row].title return cell } }
关键说明
- 数据传递方向1(主→详情):通过直接给详情页的
currentItems属性赋值,把主控制器的数据源传过去,这样详情页能展示相同的数据。 - 数据传递方向2(详情→主):用闭包
onItemAdded来回传新数据,这种方式比代理更轻量,适合简单的回调场景。如果你的场景更复杂(比如需要回传多种事件),也可以用代理模式。 - 避免循环引用:在主控制器中用
[weak self]捕获,防止闭包持有主控制器导致内存泄漏。
内容的提问来源于stack exchange,提问作者Matteo Negroni
相关产品推荐
相关产品推荐

