Swift - 将 [String: Any] 的数组保存到 NSUserDefaults
Swift - Save array of [String: Any] to NSUserDefauls
我发现这个扩展使用 Codable 保存到 NSUserDefaults
extension UserDefaults {
func decode<T : Codable>(for type : T.Type, using key : String) -> T? {
let defaults = UserDefaults.standard
guard let data = defaults.object(forKey: key) as? Data else {return nil}
let decodedObject = try? PropertyListDecoder().decode(type, from: data)
return decodedObject
}
func encode<T : Codable>(for type : T, using key : String) {
let defaults = UserDefaults.standard
let encodedData = try? PropertyListEncoder().encode(type)
defaults.set(encodedData, forKey: key)
defaults.synchronize()
}
}
但据我所知,我有一个错误 Type 'OfflineRequest' does not conform to protocol 'Decodable'
看起来是因为 Any
。
我有下一个要保存的结构:
struct OfflineRequest: Codable {
let url: String
let params: [String: Any]
}
这个想法是持久存储由于任何连接问题而失败的请求堆栈(数组)。所以我有 Core Data 数据模型,并且在将其发送到服务器之前将其属性转换为 [String: Any]。但现在我想创建离线优先算法。因此,如果用户离线,我想持久存储 url 和 [String: Any] 参数。这种情况下如何正确处理does not conform to protocol 'Decodable'
?
你因为 [String:Any]
而出错我建议你使用 JSONSerialization.data
将 [String:Any]
转换为 Data
然后你可以像这样使用
struct OfflineRequest: Codable {
let url: String
let params: Data
enum CodingKeys: String, CodingKey {
case url
case params
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
params = try values.decode(Data.self, forKey: .params)
url = try values.decode(String.self, forKey: .url)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(url, forKey: .url)
try container.encode(params, forKey: .params)
}
}
您可以使用 JSONSerialization.data(withJSONObject: Any)
对字典进行编码,并使用 JSONSerialization.JSONObject(with: Data)
对其进行解码。你只需要确保你传递了一个有效的 json 对象(在本例中是一个字典),如果你传递一个类型如 Date
的字典,它将崩溃。像这样尝试:
struct OfflineRequest: Codable {
let url: String
let params: [String: Any]
}
extension OfflineRequest {
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
url = try container.decode(String.self)
params = try JSONSerialization.jsonObject(with: container.decode(Data.self)) as? [String:Any] ?? [:]
}
func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(url)
try container.encode(JSONSerialization.data(withJSONObject: params))
}
}
let test = [OfflineRequest(url: "http://www.google.com", params: ["a":"1","b":"test", "c":["d":"test"]])]
let data = try! JSONEncoder().encode(test)
let loaded = try! JSONDecoder().decode([OfflineRequest].self, from: data)
print(loaded) // [__lldb_expr_3.OfflineRequest(url: "http://www.google.com", params: ["b": test, "a": 1, "c": {\n d = test;\n}])]\n"
我发现这个扩展使用 Codable 保存到 NSUserDefaults
extension UserDefaults {
func decode<T : Codable>(for type : T.Type, using key : String) -> T? {
let defaults = UserDefaults.standard
guard let data = defaults.object(forKey: key) as? Data else {return nil}
let decodedObject = try? PropertyListDecoder().decode(type, from: data)
return decodedObject
}
func encode<T : Codable>(for type : T, using key : String) {
let defaults = UserDefaults.standard
let encodedData = try? PropertyListEncoder().encode(type)
defaults.set(encodedData, forKey: key)
defaults.synchronize()
}
}
但据我所知,我有一个错误 Type 'OfflineRequest' does not conform to protocol 'Decodable'
看起来是因为 Any
。
我有下一个要保存的结构:
struct OfflineRequest: Codable {
let url: String
let params: [String: Any]
}
这个想法是持久存储由于任何连接问题而失败的请求堆栈(数组)。所以我有 Core Data 数据模型,并且在将其发送到服务器之前将其属性转换为 [String: Any]。但现在我想创建离线优先算法。因此,如果用户离线,我想持久存储 url 和 [String: Any] 参数。这种情况下如何正确处理does not conform to protocol 'Decodable'
?
你因为 [String:Any]
而出错我建议你使用 JSONSerialization.data
[String:Any]
转换为 Data
然后你可以像这样使用
struct OfflineRequest: Codable {
let url: String
let params: Data
enum CodingKeys: String, CodingKey {
case url
case params
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
params = try values.decode(Data.self, forKey: .params)
url = try values.decode(String.self, forKey: .url)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(url, forKey: .url)
try container.encode(params, forKey: .params)
}
}
您可以使用 JSONSerialization.data(withJSONObject: Any)
对字典进行编码,并使用 JSONSerialization.JSONObject(with: Data)
对其进行解码。你只需要确保你传递了一个有效的 json 对象(在本例中是一个字典),如果你传递一个类型如 Date
的字典,它将崩溃。像这样尝试:
struct OfflineRequest: Codable {
let url: String
let params: [String: Any]
}
extension OfflineRequest {
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
url = try container.decode(String.self)
params = try JSONSerialization.jsonObject(with: container.decode(Data.self)) as? [String:Any] ?? [:]
}
func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(url)
try container.encode(JSONSerialization.data(withJSONObject: params))
}
}
let test = [OfflineRequest(url: "http://www.google.com", params: ["a":"1","b":"test", "c":["d":"test"]])]
let data = try! JSONEncoder().encode(test)
let loaded = try! JSONDecoder().decode([OfflineRequest].self, from: data)
print(loaded) // [__lldb_expr_3.OfflineRequest(url: "http://www.google.com", params: ["b": test, "a": 1, "c": {\n d = test;\n}])]\n"