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
相关产品推荐
相关产品推荐

