URL Scheme触发时,如何从BViewController向AViewController传递数据?
嘿,我完全理解你的困扰——全局变量容易导致代码耦合和不可预测的状态问题,直接在AppDelegate里操作ViewController也违背了MVC的职责分离原则。这里有几个更优雅的解决方案,你可以根据自己的应用场景选择:
方案1:使用NotificationCenter传递数据
这是一种轻量的解耦方式,通过通知触发数据传递逻辑:
- 在
BViewController中注册一个特定通知,监听URL Scheme的触发事件 - 当AppDelegate接收到URL Scheme调用时,发送通知
BViewController收到通知后,将自身的数据通过另一个通知转发给AViewController- 注意在
BViewController销毁时移除通知监听,避免内存泄漏
示例代码:
// BViewController 注册通知 override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(handleURLSchemeTrigger), name: NSNotification.Name("URLSchemeTriggered"), object: nil ) } @objc private func handleURLSchemeTrigger() { // 转发B的数据给A NotificationCenter.default.post( name: NSNotification.Name("PassBDataToA"), object: self.targetData ) } // 销毁时移除监听 deinit { NotificationCenter.default.removeObserver(self) } // AppDelegate 触发URL Scheme时发送通知 func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { NotificationCenter.default.post(name: NSNotification.Name("URLSchemeTriggered"), object: nil) // 后续处理AViewController的展示逻辑 return true } // AViewController 接收数据 override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(receiveBData(_:)), name: NSNotification.Name("PassBDataToA"), object: nil ) } @objc private func receiveBData(_ notification: Notification) { if let data = notification.object as? YourDataType { // 更新A的UI或业务逻辑 } }
方案2:封装单例状态管理类(比全局变量更可控)
创建一个专门负责数据状态管理的单例类,封装数据的读写逻辑,还可以添加监听回调,避免全局变量的混乱:
class AppDataManager { static let shared = AppDataManager() private var bData: YourDataType? private var dataUpdateHandler: ((YourDataType?) -> Void)? // 私有初始化,保证单例唯一性 private init() {} // 存储B的数据 func saveBData(_ data: YourDataType) { bData = data dataUpdateHandler?(bData) } // 获取B的数据 func getBData() -> YourDataType? { return bData } // 添加数据更新监听 func addDataUpdateListener(_ handler: @escaping (YourDataType?) -> Void) { dataUpdateHandler = handler } }
使用方式:
- 在
BViewController中更新数据:AppDataManager.shared.saveBData(yourData) - 在
AViewController中获取或监听数据:
override func viewDidLoad() { super.viewDidLoad() // 直接获取当前数据 if let data = AppDataManager.shared.getBData() { updateUI(with: data) } // 或监听后续数据变化 AppDataManager.shared.addDataUpdateListener { [weak self] data in guard let self = self, let data = data else { return } self.updateUI(with: data) } }
方案3:使用Coordinator模式(适合复杂导航场景)
如果你的应用导航逻辑比较复杂,Coordinator模式可以将导航和数据传递逻辑从ViewController中抽离出来,让ViewController只专注于业务展示:
class AppCoordinator { static let shared = AppCoordinator() var currentNavigationController: UINavigationController? func handleURLScheme() { // 检查当前导航栈中是否存在BViewController if let bVC = currentNavigationController?.viewControllers.first(where: { $0 is BViewController }) as? BViewController { // 获取B的数据并初始化A let aVC = AViewController() aVC.receivedData = bVC.targetData currentNavigationController?.pushViewController(aVC, animated: true) } else { // 没有B的情况,直接打开A let aVC = AViewController() currentNavigationController?.pushViewController(aVC, animated: true) } } }
在AppDelegate中调用:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { AppCoordinator.shared.handleURLScheme() return true }
方案4:使用Combine框架(iOS 13+ 现代方案)
利用Combine的响应式特性,通过CurrentValueSubject发布数据,让AViewController订阅数据流,自动获取最新数据:
import Combine class DataPublisher { static let shared = DataPublisher() // 用CurrentValueSubject保存并发布数据 let bDataSubject = CurrentValueSubject<YourDataType?, Never>(nil) private init() {} func updateBData(_ data: YourDataType) { bDataSubject.send(data) } }
使用方式:
BViewController中更新数据:DataPublisher.shared.updateBData(yourData)AViewController中订阅数据:
var cancellables = Set<AnyCancellable>() override func viewDidLoad() { super.viewDidLoad() DataPublisher.shared.bDataSubject .receive(on: DispatchQueue.main) // 切换到主线程更新UI .sink { [weak self] data in guard let self = self, let data = data else { return } self.updateUI(with: data) } .store(in: &cancellables) }
这些方案都能有效避免你提到的两个问题:既不用全局变量,也不需要在AppDelegate中直接操作ViewController。简单场景可以选NotificationCenter或封装的状态管理器;复杂导航场景推荐Coordinator模式;iOS 13+的项目用Combine会更优雅。
内容的提问来源于stack exchange,提问作者FoxGlove
相关产品推荐
相关产品推荐

