Swift中解析远程推送通知数据遇崩溃,求安全解析方案
iOS推送通知userInfo安全解析方案
兄弟,我太懂你这种解析推送userInfo时崩溃的糟心了!之前我也踩过类似的坑——直接强制类型转换或者解包,稍有不慎就触发崩溃。给你分享几个稳得一批的解析方法,再也不用担心翻车:
方法一:安全可选绑定+默认值(最直接)
这种方法不需要额外封装,每一步都做安全的类型校验,失败时给默认值,完全避免强制解包的风险:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("FFTF", "didReceiveRemoteNotification", userInfo) // 解析content-available(嵌套在aps字典中) let contentAvailable = (userInfo["aps"] as? [String: Any])?["content-available"] as? Int ?? 0 // 解析FcmNotificationStatus let fcmNotificationStatus = userInfo["FcmNotificationStatus"] as? Int ?? 0 // 解析ListItemIds(字符串数组) let listItemIds = userInfo["ListItemIds"] as? [String] ?? [] // 解析UserId let userId = userInfo["UserId"] as? Int ?? 0 // 后续业务逻辑使用这些字段 print("contentAvailable: \(contentAvailable), fcmStatus: \(fcmNotificationStatus), listItemIds: \(listItemIds), userId: \(userId)") completionHandler(.newData) }
为什么不会崩溃?
- 用
as?做安全类型转换,失败时会返回nil - 用
??给nil情况设置默认值,保证变量始终有合法值 - 嵌套字段先校验外层字典的存在,再取内层值,避免链式解包崩溃
方法二:用Codable模型化解析(更优雅易维护)
如果推送字段较多,或者后续需要频繁解析,推荐用Codable把数据模型化,代码可读性和维护性都会提升很多:
首先定义对应推送数据的结构体:
struct PushNotificationPayload: Codable { let aps: Aps let fcmNotificationStatus: Int let listItemIds: [String] let userId: Int // 处理aps内部的字段映射(推送里的content-available转成Swift驼峰命名) struct Aps: Codable { let contentAvailable: Int enum CodingKeys: String, CodingKey { case contentAvailable = "content-available" } } // 处理顶层字段的映射(和推送返回的字段名对应) enum CodingKeys: String, CodingKey { case aps case fcmNotificationStatus = "FcmNotificationStatus" case listItemIds = "ListItemIds" case userId = "UserId" } }
然后在推送回调里解析:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("FFTF", "didReceiveRemoteNotification", userInfo) // 把userInfo转成Data,再用JSONDecoder解析成模型 guard let jsonData = try? JSONSerialization.data(withJSONObject: userInfo, options: []), let payload = try? JSONDecoder().decode(PushNotificationPayload.self, from: jsonData) else { // 解析失败时的降级处理 print("推送数据解析失败") completionHandler(.failed) return } // 成功解析后直接使用模型字段 print("contentAvailable: \(payload.aps.contentAvailable), fcmStatus: \(payload.fcmNotificationStatus), listItemIds: \(payload.listItemIds), userId: \(payload.userId)") completionHandler(.newData) }
避坑提醒
- 绝对禁止用
as!强制类型转换:哪怕你觉得字段肯定存在,服务器也可能出现版本变更、推送异常等情况,强制转换只会让崩溃找上门 - 给字段设置合理默认值:比如Int类型用0,数组用空数组,避免
nil导致的后续逻辑异常 - 注意字段名大小写:推送返回的字段名和Swift里的命名要严格对应,或者用CodingKeys做映射
内容的提问来源于stack exchange,提问作者A.s.ALI
相关产品推荐
相关产品推荐

