Reputation: 35963
I have a struct like this
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)
}
I need to transform that into JSON by using Codable, so I do
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: Cannot automatically synthesize 'Decodable' because 'State' does not conform to 'Decodable' and the same error for the point.
The problem here appears to be that both properties are @State
.
How do I solve that?
Upvotes: 1
Views: 400
Reputation: 52426
I'd suggest encapsulating id, name, code, position, scale into their own encodable struct and use that as a single @State property on SymbolView. Then, just encode/decode the model rather than trying to encode/decode the View.
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
}
}
Or, keep your original code and write a custom 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)
}
}
Upvotes: 2