我尝试通过将
@AppStorage
添加到结构中,将 String
与包含 UUID
和 RawRepresentable
的数据结构一起使用。看来 RawRepresentable
导致 JSONEncoder.encode()
函数行为异常。
以下最小可重现示例在调用
print(p.rawValue)
时会导致无限循环。在这种情况下,会重复打印"rawValue 1"
,直到应用程序最终崩溃。
Printer(name: "HP", id: CBAA56C5-7E14-4351-BFF4-75413AE8B5C5)
rawValue 1
rawValue 1
rawValue 1
...
删除
: RawRepresentable
会使调用正常工作,但需要将此结构与 @AppStorage
一起使用。
Printer(name: "HP", id: CBAA56C5-7E14-4351-BFF4-75413AE8B5C5)
rawValue 1
rawValue 2
rawValue 3
{"name":"HP","id":"CBAA56C5-7E14-4351-BFF4-75413AE8B5C5"}
我做错了什么吗?或者这可能是一个已知的错误并有解决方法?
注意:这是一个简化的示例。我的
Printer
结构有点复杂`.
import SwiftUI
struct Printer: Codable {
let name: String
let id: UUID
}
extension Printer: RawRepresentable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode(Printer.self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
print("rawValue 1")
guard let data = try? JSONEncoder().encode(self) else { return "{}" }
print("rawValue 2")
guard let result = String(data: data, encoding: .utf8) else { return "{}" }
print("rawValue 3")
return result
}
}
struct ContentView: View {
// Ideally I want to use @AppStorage here...
// @AppStorage("printer") var p = Printer(name: "HP", id: UUID())
@State private var p = Printer(name: "HP", id: UUID())
var body: some View {
VStack {
Text("Hello World!")
.onAppear {
print(p)
print(p.rawValue)
}
}
}
}
你的问题是来自 stdlib 的定义:
extension RawRepresentable where Self : Decodable, Self.RawValue == String {
/// Creates a new instance by decoding from the given decoder, when the
/// type's `RawValue` is `String`.
///
/// This initializer throws an error if reading from the decoder fails, or
/// if the data read is corrupted or otherwise invalid.
///
/// - Parameter decoder: The decoder to read data from.
public init(from decoder: any Decoder) throws
}
RawRepresentable 事物会自动获得一个
encode(to:)
方法,该方法是通过对其 rawValue
进行编码来实现的,这是递归的。
您需要手动编写
encode(to:)
和 init(from:)
方法来覆盖默认的 RawRepresentable 实现。