使用可选的初始化程序将自定义数据类型存储在@AppStorage 中?
Store custom data type in @AppStorage with optional initializer?
我正在尝试将自定义数据类型存储到 AppStorage
。为此,该模型符合 RawRepresentable
(遵循此 tutorial)。它工作正常,但是当我初始化 @AppStorage
变量时,它需要一个初始 UserModel
值。我想让变量可选,所以如果用户注销,它可以是 nil。这可能吗?
在 class / 视图中,我可以这样初始化:
@AppStorage("user_model") private(set) var user: UserModel = UserModel(id: "", name: "", email: "")
但我想这样初始化:
@AppStorage("user_model") private(set) var user: UserModel?
型号:
struct UserModel: Codable {
let id: String
let name: String
let email: String
enum CodingKeys: String, CodingKey {
case id
case name
case email
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
do {
id = try String(values.decode(Int.self, forKey: .id))
} catch DecodingError.typeMismatch {
id = try String(values.decode(String.self, forKey: .id))
}
self.name = try values.decode(String.self, forKey: .name)
self.email = try values.decode(String.self, forKey: .email)
}
init(id: String, name: String, email: String) {
self.id = id
self.name = name
self.email = email
}
}
// MARK: RAW REPRESENTABLE
extension UserModel: RawRepresentable {
// RawRepresentable allows a UserModel to be store in AppStorage directly.
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode(UserModel.self, from: data)
else {
return nil
}
self = result
}
var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(email, forKey: .email)
}
}
下面的代码可以工作,因为您添加了一致性 UserModel: RawRepresentable
:
@AppStorage("user_model") private(set) var user: UserModel = UserModel(id: "", name: "", email: "")
如果您希望以下内容起作用,您需要对 UserModel?
执行相同的操作:
@AppStorage("user_model") private(set) var user: UserModel? = nil
这是一个可能的解决方案:
extension Optional: RawRepresentable where Wrapped == UserModel {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode(UserModel.self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: UserModel.CodingKeys.self)
try container.encode(self?.id, forKey: .id)
try container.encode(self?.name, forKey: .name)
try container.encode(self?.email, forKey: .email)
}
}
注意:我重用了您已经为 UserModel: RawRepresentable
使用的实现 - 对于这种情况可能需要进行一些更正。
也因为你符合 Optional: RawRepresentable
你需要
UserModel
public也是。
任何可选的可能通用方法 Codable
:
extension Optional: RawRepresentable where Wrapped: Codable {
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let json = String(data: data, encoding: .utf8)
else {
return "{}"
}
return json
}
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let value = try? JSONDecoder().decode(Self.self, from: data)
else {
return nil
}
self = value
}
}
有了这个,any Codable
现在可以保存在应用存储中:
@AppStorage("user_model") var user: UserModel? = nil
我正在尝试将自定义数据类型存储到 AppStorage
。为此,该模型符合 RawRepresentable
(遵循此 tutorial)。它工作正常,但是当我初始化 @AppStorage
变量时,它需要一个初始 UserModel
值。我想让变量可选,所以如果用户注销,它可以是 nil。这可能吗?
在 class / 视图中,我可以这样初始化:
@AppStorage("user_model") private(set) var user: UserModel = UserModel(id: "", name: "", email: "")
但我想这样初始化:
@AppStorage("user_model") private(set) var user: UserModel?
型号:
struct UserModel: Codable {
let id: String
let name: String
let email: String
enum CodingKeys: String, CodingKey {
case id
case name
case email
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
do {
id = try String(values.decode(Int.self, forKey: .id))
} catch DecodingError.typeMismatch {
id = try String(values.decode(String.self, forKey: .id))
}
self.name = try values.decode(String.self, forKey: .name)
self.email = try values.decode(String.self, forKey: .email)
}
init(id: String, name: String, email: String) {
self.id = id
self.name = name
self.email = email
}
}
// MARK: RAW REPRESENTABLE
extension UserModel: RawRepresentable {
// RawRepresentable allows a UserModel to be store in AppStorage directly.
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode(UserModel.self, from: data)
else {
return nil
}
self = result
}
var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(email, forKey: .email)
}
}
下面的代码可以工作,因为您添加了一致性 UserModel: RawRepresentable
:
@AppStorage("user_model") private(set) var user: UserModel = UserModel(id: "", name: "", email: "")
如果您希望以下内容起作用,您需要对 UserModel?
执行相同的操作:
@AppStorage("user_model") private(set) var user: UserModel? = nil
这是一个可能的解决方案:
extension Optional: RawRepresentable where Wrapped == UserModel {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode(UserModel.self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: UserModel.CodingKeys.self)
try container.encode(self?.id, forKey: .id)
try container.encode(self?.name, forKey: .name)
try container.encode(self?.email, forKey: .email)
}
}
注意:我重用了您已经为 UserModel: RawRepresentable
使用的实现 - 对于这种情况可能需要进行一些更正。
也因为你符合 Optional: RawRepresentable
你需要
UserModel
public也是。
任何可选的可能通用方法 Codable
:
extension Optional: RawRepresentable where Wrapped: Codable {
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let json = String(data: data, encoding: .utf8)
else {
return "{}"
}
return json
}
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let value = try? JSONDecoder().decode(Self.self, from: data)
else {
return nil
}
self = value
}
}
有了这个,any Codable
现在可以保存在应用存储中:
@AppStorage("user_model") var user: UserModel? = nil