编码具有 @State 的结构

Encoding a struct that has @State

我有这样的结构

struct SymbolView: View, Identifiable {
  let id = UUID()
  
  var name:String
  var code:String
  @State var position = CGPoint(x:100, y:100)
  @State var scale = CGFloat(1)
} 

我需要使用 Codable 将其转换为 JSON,所以我这样做了

extension SymbolView: Codable{
  private enum CodingKeys: String, CodingKey {
    case name
    case code
    case position
    case scale
  }
  
  public func encode(to encoder:Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    do {
      try container.encode(self.name, forKey: .name)
      try container.encode(self.code, forKey: .code)
      try container.encode(self.position, forKey: .position)
      try container.encode(self.scale, forKey: .scale)
    } catch (let error) {
      print(error.localizedDescription)
    }
  }
}

errors: 不能自动合成'Decodable' 因为'State'不符合'Decodable'和点一样的错误。

这里的问题似乎是两个属性都是 @State

我该如何解决?

我建议将 id、名称、代码、位置、比例封装到它们自己的可编码结构中,并将其用作 SymbolView 上的单个 @State 属性。然后,只是 encode/decode 模型而不是尝试 encode/decode 视图。

struct SymbolModel : Identifiable, Codable {
    var id = UUID()
    var name:String
    var code:String
    var position = CGPoint(x:100, y:100)
    var scale = CGFloat(1)
}

struct SymbolView: View {
    @State var symbol : SymbolModel
    
    var body: some View {
        Text("Symbol...")
    }
    
    func encodeSymbolModel() -> Data? {
        try? JSONEncoder().encode(symbol)
    }
}

struct ContentView: View {
    @State var symbolModel : SymbolModel?
    
    var body: some View {
        if let symbolModel = symbolModel {
            SymbolView(symbol: symbolModel)
        }
    }
    
    func decodeSymbolFromData(data: Data) -> SymbolModel? {
        do {
            return try JSONDecoder().decode(SymbolModel.self, from: data)
        } catch {
            print(error)
        }
        return nil
    }
}

或者,保留您的原始代码并编写自定义代码 init(from decoder):

extension SymbolView: Codable {
    private enum CodingKeys: String, CodingKey {
        case name
        case code
        case position
        case scale
    }
    
    public func encode(to encoder:Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        do {
            try container.encode(self.name, forKey: .name)
            try container.encode(self.code, forKey: .code)
            try container.encode(self.position, forKey: .position)
            try container.encode(self.scale, forKey: .scale)
        } catch (let error) {
            print(error.localizedDescription)
        }
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        code = try values.decode(String.self, forKey: .code)
        position = try values.decode(CGPoint.self, forKey: .position)
        scale = try values.decode(CGFloat.self, forKey: .scale)
    }
}