Kex*_*Kex 4 ios swift swiftui appstorage
我有一个想要存储在的自定义结构AppStorage:
struct Budget: Codable, RawRepresentable {
enum CodingKeys: String, CodingKey {
case total, spent
}
var total: Double
var spent: Double
init(total: Double = 5000.0, spent: Double = 3000.0) {
self.total = total
self.spent = spent
}
init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode(Budget.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
}
}
Run Code Online (Sandbox Code Playgroud)
那么我有以下观点:
struct DemoView: View {
@AppStorage(UserDefaults.StorageKeys.budget.rawValue) var budget = Budget()
var body: some View {
Button("Update") {
budget.total = 10
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我点击按钮时,应用程序崩溃并显示Thread 1: EXC_BAD_ACCESSon guard let data = try? JSONEncoder().encode(self)for rawValuein Budget。我在这里做错了什么?
您正在遇到无限递归。这是因为符合两者的类型Encodable会RawRepresentable自动获取此encode(to:)实现(source),该实现对原始值进行编码。这意味着当你调用 时JSONEncoder().encode,它会尝试调用 的 getter rawValue,从而调用JSONEncoder().encode,形成无限递归。
为了解决这个问题,你可以encode(to:)显式地实现:
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(total, forKey: .total)
try container.encode(spent, forKey: .spent)
}
Run Code Online (Sandbox Code Playgroud)
请注意,您还应该init(from:)显式实现,因为您还获得了一个尝试将 JSON 解码为单个 JSON 字符串的init(from:)实现(source),而您当然不希望这样做。
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
total = try container.decode(Double.self, forKey: .total)
spent = try container.decode(Double.self, forKey: .spent)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
334 次 |
| 最近记录: |