iosswiftenumsnscodingnskeyedarchiver

Cannot use NSKeyedArchiver to save my model


I am getting model from Api and it looks like this:

class Device : NSObject, Codable, NSCoding{
    var deviceId : Int?
    var driver : String?
    var address : String?
    var type : DeviceTypes? // Enum type

    func encode(with coder: NSCoder) {
        coder.encode(self.deviceId, forKey: "deviceId")
        coder.encode(self.driver, forKey: "driver")
        coder.encode(self.address, forKey: "address")
        coder.encode(self.type, forKey: CodingKeys.type.rawValue)
    }
    required init?(coder: NSCoder) {
        super.init()

        self.deviceId = coder.decodeInteger(forKey: "deviceId")
        self.driver = coder.decodeObject(forKey: "driver") as? String
        self.address = coder.decodeObject(forKey: "address") as? String
        self.type = coder.decodeObject(forKey: CodingKeys.type.rawValue) as? DeviceTypes
    }

    private enum CodingKeys : String, CodingKey{
        case deviceId, address, type, deviceType
    }
}

Then I am adding some elements to array and it works but when I am trying to archive it with NSKeyedArchiver it throws an Exception :

[__SwiftValue encodeWithCoder:]: unrecognized selector sent to instance

DeviceTypes

enum DeviceTypes : Int, Codable{
    case SYSTEM
    case CE
    case CZ
    case ST
    case KA
    case CR
    case EX
    case DR
    case KL
    case WE
    case WY
    case WL
    case TR
    case LI
    case BR = 30
    case DC = 32
}

Solution

  • Your problem is NSCoding is only available for class types. Any attempt to conform DeviceTypes to NSCoding will result in an error

    enum DeviceTypes : Int, Codable, NSCoding {
    

    Non-class type 'DeviceTypes' cannot conform to class protocol 'NSCoding'

    One solution is to convert back and forth from the enum type in your NSCoding methods.

    Note that NSCoding is soft deprecated for NSSecureCoding so you should use that conformance to avoid future support issues.

    class Device : NSObject, NSSecureCoding {
    
        static var supportsSecureCoding: Bool = true
    
        var deviceId : Int?
        var driver : String?
        var address : String?
        var type : DeviceTypes? // Enum type
    
        func encode(with coder: NSCoder) {
            coder.encode(self.deviceId, forKey: "deviceId")
            coder.encode(self.driver, forKey: "driver")
            coder.encode(self.address, forKey: "address")
    
            coder.encode(self.type?.rawValue, forKey: "type")
        }
    
        required init?(coder: NSCoder) {
            super.init()
    
            self.deviceId = coder.decodeInteger(forKey: "deviceId")
            self.driver = coder.decodeObject(forKey: "driver") as? String
            self.address = coder.decodeObject(forKey: "address") as? String
    
            let rawtype = coder.decodeInteger(forKey: "type")
            self.type = DeviceTypes(rawValue: rawtype)
        }
    
    }
    

    You haven't supplied all the code in your Device class as your post fragment doesn't compile with Codable conformance so I can't guess at what your system really requires in terms of JSON support.