make CAShapeLayer and CGPath conform to Codable or to NSCoding

298 Views Asked by At

I'm trying to save and get info about CAShapeLayers at .json files, using Codable protocol, but have an error:

public class Node: Codable {


public var name: String = ""

public var path: CGPath?
    
public var baseLayer: CAShapeLayer?


public required init(from decoder: Decoder) throws {
    let container = try? decoder.container(keyedBy: NodeCodingKeys.self)
           
    let _name = try container?.decodeIfPresent(String.self, forKey: NodeCodingKeys.name)
    
    let _baseLayer = try container?.decodeIfPresent(CAShapeLayer.self, forKey: NodeCodingKeys.baseLayer)
    name = _name ?? ""
}

public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: NodeCodingKeys.self)
    try container.encode(name, forKey: NodeCodingKeys.name)
}
}

public enum NodeCodingKeys: CodingKey {
    
    case path
    case name
    case baseLayer
    
}

enter image description here

And the same for CGPath. Is there any way to save/receive them to/from device?

1

There are 1 best solutions below

0
nastassia On BEST ANSWER

I couldn't find a way to make CAShapeLayer conforms to Codable, so I created class for my data object:

public class ImageNode: NSObject, NSCoding, NSSecureCoding {
    public static var supportsSecureCoding = true
    var name: NSString
    var baseLayer: CAShapeLayer
    
    init(name: NSString,
         baseLayer: CAShapeLayer
         ) {
            self.name = name
            self.baseLayer = baseLayer
        }
    
    public func encode(with coder: NSCoder) {
        
        coder.encode(name, forKey: "name")
        coder.encode(baseLayer, forKey: "baseLayer")        
    }
    
    public required convenience init?(coder: NSCoder) {
        guard let name = coder.decodeObject(forKey: "name") as? NSString
            else { return nil }
        guard let baseLayer = coder.decodeObject(forKey: "baseLayer") as? CAShapeLayer
            else { return nil }
             
        print("decode node")
            self.init(
                name: name,
                baseLayer: baseLayer
            )
    } }

which works nice with NSKeyedArchiver and NSKeyedUnarchiver for saving data to file and retrieving it. Maybe this solution will helps someone.