如何为TODO分类?iOS双ViewController数据交互与跳转问题
解决iOS双ViewController双向数据传递问题
Hey,先帮你指出现有代码里的一个小问题:你在tableView(_:didSelectRowAt:)方法里同时执行了present(vc!, animated: true)和performSegue(withIdentifier: "hhh", sender: indexPath),这会导致两次跳转,得去掉其中一个,推荐用Segue的方式,更符合Storyboard的使用规范。
接下来重点说双向数据传递的实现,iOS里常用两种方案:闭包(Closure)和代理(Delegate),这里闭包实现更简洁,适合你的场景,下面是一步步的具体方案:
1. 调整数据结构(关联分类与TODO项)
首先你需要把分类名和对应的TODO项关联起来,原来的todos数组只是分类列表,建议在FirstViewController里新增一个字典来存储对应关系:
// FirstViewController.swift var todos: [String] = ["工作", "生活", "学习"] // 分类列表 var todoMap: [String: [String]] = [:] // 存储「分类名: 对应TODO数组」,初始化时可给每个分类默认空数组
2. 修改SecondViewController,添加闭包用于回传数据
在SecondViewController里定义闭包属性,用来把更新后的TODO数组回传给第一个页面:
// SecondViewController.swift var categoryName: String = "" // 接收从FirstVC传来的分类名 var todoItems: [String] = [] // 当前分类的TODO列表(替换原来的SecondArray,符合Swift命名规范) // 定义回传闭包:参数是更新后的TODO数组,无返回值 var onTodoUpdated: (([String]) -> Void)? // 假设你有返回按钮,点击时触发回传 @IBAction func backBtnTapped(_ sender: UIButton) { // 调用闭包回传数据 onTodoUpdated?(todoItems) dismiss(animated: true, completion: nil) } // 如果是导航控制器的默认返回按钮,可在viewWillDisappear里触发回传 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 仅当手动返回上一页时触发,避免其他场景(如push到新页面)误触发 if isMovingFromParent { onTodoUpdated?(todoItems) } }
3. 完善FirstViewController的跳转与数据接收逻辑
修改prepare(for:sender:)方法,传递分类数据并设置闭包接收回传结果:
// FirstViewController.swift override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "hhh" { guard let secondVC = segue.destination as? SecondViewController, let indexPath = sender as? IndexPath else { return } let selectedCategory = todos[indexPath.row] // 传递分类名和当前分类的TODO列表 secondVC.categoryName = selectedCategory secondVC.todoItems = todoMap[selectedCategory] ?? [] // 设置闭包,接收回传的更新后TODO数组 secondVC.onTodoUpdated = { [weak self] updatedTodos in guard let self = self else { return } // 更新本地字典里的对应分类数据 self.todoMap[selectedCategory] = updatedTodos // 可选:如果需要在FirstVC的单元格显示TODO数量,可刷新对应行 self.tableView.reloadRows(at: [indexPath], with: .automatic) } } } // 修正didSelectRowAt方法,去掉重复跳转 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { performSegue(withIdentifier: "hhh", sender: indexPath) tableView.deselectRow(at: indexPath, animated: true) let selectedCategory = todos[indexPath.row] print("选中分类: \(selectedCategory)") print("行号: \(indexPath.row)") }
逻辑说明
- 正向传递:点击FirstVC的单元格时,通过Segue把分类名和该分类已有的TODO列表传给SecondVC,SecondVC就能展示对应内容。
- 反向回传:当用户在SecondVC里添加/修改TODO项后,返回时调用闭包把更新后的数组传给FirstVC,FirstVC更新本地字典,确保下次进入该分类时能看到最新数据。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

