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

iOS Swift中将推送通知数据存入UserDefaults返回nil问题

问题原因

代码取值返回nil是三个问题叠加导致的:

  • 变量未初始化:你声明的var pushInfo: PushInfo?默认值就是nil,没有实际创建PushInfo实例。后续写的pushInfo?.body = xxx属于可选链赋值,当可选变量本身为nil时,所有赋值操作都会直接跳过不执行,这三行赋值代码全程没有生效,pushInfo从始至终都是空值。
  • 存储类型不符合规范:UserDefaults仅支持直接存储NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary这几类plist兼容类型,不支持直接存储自定义Swift结构体,你直接传入自定义结构体调用setValue,存储操作本身就会失败。另外你的PushInfo结构体只遵守了Encodable编码协议,没有遵守Decodable解码协议,就算把数据存进去了也无法反向解析成模型实例。
  • 存取键方法不匹配:存值时用的是KVC接口setValue(_:forKeyPath:),取值时用的是object(forKey:),两个接口的键匹配逻辑存在差异,即使数据存入成功也会因为键不匹配取不到值。
修复方案
  • 模型改遵守Codable协议(同时包含编码、解码能力)
  • 显式初始化PushInfo实例,不要对空可选值做属性赋值
  • 存值前先通过JSONEncoder把模型序列化成Data类型,调用UserDefaults的set(_:forKey:)方法存储,不要用KVC接口
  • 取值时先取出存储的Data,再通过JSONDecoder反序列化成PushInfo模型
修复后可直接运行的代码
// 模型遵守Codable协议,支持序列化/反序列化
struct PushInfo: Codable {
    var body: String
    var title: String
    var url: String
}

// 提前校验推送数据格式,显式初始化模型实例
guard let pushDict = data as? [String: Any] else { return }
let pushInfo = PushInfo(
    body: pushDict["body"] as? String ?? "",
    title: pushDict["title"] as? String ?? "",
    url: pushDict["url"] as? String ?? ""
)

// 序列化为Data后再存入UserDefaults
do {
    let encodedData = try JSONEncoder().encode(pushInfo)
    UserDefaults.standard.set(encodedData, forKey: "PushInfo")
} catch {
    print("推送数据存储失败: \(error.localizedDescription)")
}

// 取值时先读Data,再反序列化为模型
if let storedData = UserDefaults.standard.data(forKey: "PushInfo") {
    do {
        let pushModel = try JSONDecoder().decode(PushInfo.self, from: storedData)
        print(pushModel.title)
    } catch {
        print("推送数据解析失败: \(error.localizedDescription)")
    }
}

注意:如果要存自定义类型到UserDefaults,必须先转换成上述提到的6种plist兼容类型,最通用的方案就是转成Data存储,不要尝试直接把自定义结构体/类对象塞进UserDefaults。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:27:14