0

I'm developing a graphical editor in Swift and Cocoa. I need to save and load information about objects in document.

Objects are represented by a 'Node' class and its descendants. They all implement 'Codable' protocol to make it easier to perform serialization. Therefore I need a way to instantiate an object of a proper Node's descendant during deserialization with Decoder.

I use static method 'from' which returns an instance of a Node's descendant according to its NodeType.

However, this leads to lost of boilerplate code in 'from' method.

Are there any ways of instantiating a proper descendant of a class with Codable?

import Cocoa

enum NodeType: Codable {
    case root
    case text
    case lineBreak
}


class Node: Codable {
    let type: NodeType
    let id: UUID
    
    enum CodingKeys: CodingKey {
        case type
        case id
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.type = try container.decode(NodeType.self, forKey: .type)
        self.id = try container.decode(UUID.self, forKey: .id)
    }
    
    func encode(to encoder: Encoder) throws {
        var contrainer = encoder.container(keyedBy: CodingKeys.self)
        try contrainer.encode(self.type, forKey: .type)
        try contrainer.encode(self.id, forKey: .id)
    }
    
    static func from(_ decoder: Decoder) throws -> Node {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let type = try container.decode(NodeType.self, forKey: .type)
        switch type {
            case .root:
                return try RootNode(from: decoder)
            case .text:
                return try TextNode(from: decoder)
            case .lineBreak:
                return try LineBreakNode(from: decoder)
        }
    }
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • So you are saying that the code that associates the `NodeType`s with the subclasses is "boilerplate"? How else is the decoder going to find the subclass from the JSON? – Sweeper Nov 30 '22 at 14:41
  • IMO what you have is the best you can have. The only thing you could improve is make it into more protocol/ factory implementation (rather than static function) – timbre timbre Nov 30 '22 at 15:13

0 Answers0