RawRepresentable 导致 JSONEncode 无限循环

问题描述 投票:0回答:1

我尝试通过将

@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)
                }
        }
    }
}
swift swiftui jsonencoder rawrepresentable
1个回答
0
投票

你的问题是来自 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 实现。

© www.soinside.com 2019 - 2024. All rights reserved.