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

如何为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)")
}

逻辑说明

  1. 正向传递:点击FirstVC的单元格时,通过Segue把分类名和该分类已有的TODO列表传给SecondVC,SecondVC就能展示对应内容。
  2. 反向回传:当用户在SecondVC里添加/修改TODO项后,返回时调用闭包把更新后的数组传给FirstVC,FirstVC更新本地字典,确保下次进入该分类时能看到最新数据。

内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:25:08