Swift3中如何在UIViewController获取FCM消息并展示到TableView
解决Swift 3中FCM数据从AppDelegate传到ViewController更新TableView的问题
嗨,我来帮你搞定这个事儿!你已经在AppDelegate里成功获取到FCM消息数据了,接下来要把这些数据传到UIViewController里展示在TableView上,这里有几个实用的方法,都是Swift 3里常用的,你可以根据自己的场景选:
方法一:用NotificationCenter(通知中心)传递数据
这是最常用的解耦方案,适合需要给多个页面传递数据的场景,步骤很清晰:
- 在你的ViewController里添加通知观察者
在viewDidLoad方法里注册监听,这样AppDelegate发送通知时,ViewController就能收到:
override func viewDidLoad() { super.viewDidLoad() // 注册监听FCM消息的通知 NotificationCenter.default.addObserver(self, selector: #selector(handleFCMNotification(_:)), name: NSNotification.Name(rawValue: "FCMNotificationReceived"), object: nil) } // 处理收到的FCM数据 @objc func handleFCMNotification(_ notification: Notification) { // 从通知里取出数据 guard let fcmData = notification.userInfo as? [String: Any] else { return } // 把数据添加到你的TableView数据源数组里 yourDataSourceArray.append(fcmData) // 一定要在主线程更新UI! DispatchQueue.main.async { self.yourTableView.reloadData() } } // 记得在页面销毁时移除观察者,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) }
- 在AppDelegate里发送通知
当你在didReceiveRemoteNotification方法里拿到FCM数据后,发送通知把数据传出去:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // 这里是你已经拿到的FCM数据userInfo // 发送通知传递数据 NotificationCenter.default.post(name: NSNotification.Name(rawValue: "FCMNotificationReceived"), object: nil, userInfo: userInfo) completionHandler(.newData) }
方法二:用闭包回调传递数据
如果你的ViewController是已经存在于导航栈或者当前显示的页面,用闭包会更直接,不需要依赖通知中心:
- 在AppDelegate里定义一个闭包属性
var fcmDataReceivedHandler: (([String: Any]) -> Void)?
- 在ViewController里给闭包赋值
比如在viewWillAppear或者初始化的时候,把处理数据的逻辑传给AppDelegate的闭包:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 给AppDelegate的闭包赋值 let appDelegate = UIApplication.shared.delegate as! AppDelegate appDelegate.fcmDataReceivedHandler = { [weak self] fcmData in guard let self = self else { return } // 更新数据源和TableView self.yourDataSourceArray.append(fcmData) DispatchQueue.main.async { self.yourTableView.reloadData() } } }
- 在AppDelegate里调用闭包
拿到FCM数据后,直接调用闭包把数据传过去:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // 调用闭包传递数据 fcmDataReceivedHandler?(userInfo as! [String: Any]) completionHandler(.newData) }
方法三:用单例类存储FCM数据
创建一个全局的单例类来保存所有FCM消息,ViewController可以直接读取这个单例里的数据,或者监听数据变化:
- 创建单例类
class FCMDataManager { // 单例实例 static let shared = FCMDataManager() // 存储FCM消息的数组 var fcmMessages: [[String: Any]] = [] // 可以添加一个闭包来监听数据变化 var onDataUpdated: (() -> Void)? // 添加新消息的方法 func addNewMessage(_ message: [String: Any]) { fcmMessages.append(message) // 通知监听者数据更新了 onDataUpdated?() } }
- 在AppDelegate里添加数据到单例
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { FCMDataManager.shared.addNewMessage(userInfo as! [String: Any]) completionHandler(.newData) }
- 在ViewController里监听数据变化
override func viewDidLoad() { super.viewDidLoad() // 初始化数据源为单例里的已有数据 yourDataSourceArray = FCMDataManager.shared.fcmMessages yourTableView.reloadData() // 监听数据更新 FCMDataManager.shared.onDataUpdated = { [weak self] in guard let self = self else { return } self.yourDataSourceArray = FCMDataManager.shared.fcmMessages DispatchQueue.main.async { self.yourTableView.reloadData() } } }
小提示
不管用哪种方法,一定要在主线程更新TableView,因为FCM的回调方法可能是在后台线程执行的,直接更新UI会崩溃哦!
内容的提问来源于stack exchange,提问作者Enamul Haque
相关产品推荐
相关产品推荐

