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

容器视图架构下,视图控制器间传递Song对象列表的方案咨询

嘿,针对你遇到的容器视图控制器之间的数据传递问题,我整理了几个实用的解决方案,都是iOS开发里常用的思路:

解决方案1:委托模式(Delegate Pattern)

这是iOS中处理父子/兄弟VC通信最经典的方式,利用MainVC作为中间层来传递数据,类型安全且逻辑清晰。

步骤和代码示例:

  1. 定义协议,规定数据传递的方法
  2. 在带Google Maps的容器VC中添加委托属性
  3. MainVC初始化子VC时,将自身设为委托
  4. 触发数据传递时,通过委托方法通知MainVC,再由MainVC把数据传给表格VC
// 定义数据传递协议
protocol MapContainerVCDelegate: AnyObject {
    func didSelectSongs(_ songs: [Song])
}

// 带Google Maps的容器VC
class MapContainerVC: UIViewController {
    // 弱引用避免循环引用
    weak var delegate: MapContainerVCDelegate?
    
    // 假设这是触发数据传递的逻辑(比如地图交互事件)
    func triggerSongPassing() {
        let selectedSongs: [Song] = // 你的Song列表数据
        delegate?.didSelectSongs(selectedSongs)
    }
}

// MainVC(容器持有方)
class MainVC: UIViewController, MapContainerVCDelegate {
    var mapContainerVC: MapContainerVC!
    var tableVC: TableViewController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化并添加两个子VC到容器视图的代码...
        mapContainerVC.delegate = self
    }
    
    // 实现协议方法,接收数据并传递给表格VC
    func didSelectSongs(_ songs: [Song]) {
        tableVC.updateSongList(songs)
    }
}

// 表格视图控制器
class TableViewController: UITableViewController {
    var songs: [Song] = []
    
    func updateSongList(_ newSongs: [Song]) {
        songs = newSongs
        tableView.reloadData()
    }
}
解决方案2:闭包(Closure)传递

和委托模式逻辑类似,但写法更简洁,适合简单的数据传递场景。

// 带Google Maps的容器VC
class MapContainerVC: UIViewController {
    // 定义闭包类型,用于传递Song列表
    var onSongsSelected: (([Song]) -> Void)?
    
    func triggerSongPassing() {
        let selectedSongs: [Song] = // 你的数据
        onSongsSelected?(selectedSongs)
    }
}

// MainVC
class MainVC: UIViewController {
    var mapContainerVC: MapContainerVC!
    var tableVC: TableViewController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化子VC...
        // 注入闭包,直接将数据传递给表格VC
        mapContainerVC.onSongsSelected = { [weak self] songs in
            self?.tableVC.updateSongList(songs)
        }
    }
}
解决方案3:共享数据模型(Shared Data Model)

如果你的应用有较多跨VC的数据共享需求,可以创建一个可观察的数据模型,让两个子VC都持有模型的引用,通过监听模型变化来更新UI。这里用Combine框架举例(iOS 13+支持):

import Combine

// 共享数据模型,用@Published标记可观察属性
class SongDataModel: ObservableObject {
    @Published var selectedSongs: [Song] = []
}

// MainVC
class MainVC: UIViewController {
    // 创建单例或实例化模型,传递给两个子VC
    let songDataModel = SongDataModel()
    var mapContainerVC: MapContainerVC!
    var tableVC: TableViewController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化子VC时传递模型
        mapContainerVC.songDataModel = songDataModel
        tableVC.songDataModel = songDataModel
    }
}

// 带Google Maps的容器VC
class MapContainerVC: UIViewController {
    var songDataModel: SongDataModel!
    
    func triggerSongPassing() {
        let selectedSongs: [Song] = // 你的数据
        // 直接更新模型数据,表格VC会自动监听变化
        songDataModel.selectedSongs = selectedSongs
    }
}

// 表格视图控制器
class TableViewController: UITableViewController {
    var songDataModel: SongDataModel!
    private var cancellables = Set<AnyCancellable>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 监听模型数据变化,更新UI
        songDataModel.$selectedSongs
            .receive(on: DispatchQueue.main)
            .sink { [weak self] songs in
                self?.songs = songs
                self?.tableView.reloadData()
            }
            .store(in: &cancellables)
    }
}
关于NotificationCenter的修复建议

如果你之前尝试的NotificationCenter没生效,大概率是观察者注册时机不对或者类型转换错误,可以调整成这样:

// 带Google Maps的容器VC发送通知
func triggerSongPassing() {
    let selectedSongs: [Song] = // 你的数据
    NotificationCenter.default.post(
        name: NSNotification.Name("SongsSelectedNotification"),
        object: selectedSongs
    )
}

// 表格视图控制器注册/接收通知
class TableViewController: UITableViewController {
    var songs: [Song] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 在viewDidLoad中注册观察者
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleSongsSelected(_:)),
            name: NSNotification.Name("SongsSelectedNotification"),
            object: nil
        )
    }
    
    @objc private func handleSongsSelected(_ notification: Notification) {
        // 确保类型转换正确
        guard let songs = notification.object as? [Song] else { return }
        self.songs = songs
        tableView.reloadData()
    }
    
    // 记得在销毁时移除观察者,避免内存泄漏
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

整体来说,推荐优先使用委托或闭包,这两种方式类型安全、逻辑清晰;共享数据模型适合复杂的跨VC数据场景;NotificationCenter适合松散耦合的跨模块通信,但要注意内存管理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:56:50