Search code examples
iosswiftenumsarchive

When archive object in the func encode(with aCoder: NSCoder) method crashed with swift enum in real revice


In my singleton class, I have a swift enum here:

import UIKit

enum UserType {
    case terant  // 
    case normalUser  // 
    case normalUserFinancialer  // 
}

@objc(UserStaticSwift)
class UserStaticSwift:NSObject, NSCoding {

The reported error:

With the console log:

libc++abi.dylib: terminating with uncaught exception of type NSException

In the encode:

func encode(with aCoder: NSCoder) {
    
    aCoder.encode(islogin, forKey: "islogin")
    aCoder.encode(type!, forKey: "type")  // crash here in real device 
    aCoder.encode(forOcType, forKey: "forOcType")
    aCoder.encode(username, forKey: "username")
    aCoder.encode(password, forKey: "password")
    aCoder.encode(userId, forKey: "userId")

The code here I archive my userStatic:

    userStatic.addUserInfo(type: userStatic.type!, dic: userInfoDic, closure: { (void) in
            
                // success then archive `userStatic`
                let paths:NSArray = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
                let path = paths.firstObject
                let homePath = "\(path)/\(Global.archive_userStaticData)"
                
                let _ = NSKeyedArchiver.archiveRootObject(userStatic, toFile: homePath)
                
            })

My debug when archiveRootObject:

The console log:

(lldb) po NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray

error: Couldn't materialize: couldn't get the value of void: extracting data from value failed

error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression
(lldb) po homePath

error: Couldn't materialize: couldn't get the value of void: extracting data from value failed

error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression

I have tested in simulator and device, in the simulator the issue not exist, in real device the issue comes out.


Solution

  • Try this for your Question

    func encode(with aCoder: NSCoder) {
        aCoder.encode(type.rawValue, forKey: "type")
    }
    

    For More Information

    Let Discuss this problem in details

    For example, this is my Enum:

    enum PieceType : Int {
        case empty
        case notEmpty
    }
    

    And this is my Object which is child of NSObject

    class Piece: NSObject, NSCoding {
        var islogin: Bool
        var type: PieceType
        var username: String!
        var password: String!
    
        override init() {
            islogin = false
            type = PieceType.empty
            username = ""
            password = ""
        }
    
        required init(coder aDecoder: NSCoder) {
            islogin = aDecoder.decodeBool(forKey: "islogin")
            type = PieceType(rawValue: aDecoder.decodeObject(forKey: "type") as! Int)!
            username = aDecoder.decodeObject(forKey: "username") as! String
            password = aDecoder.decodeObject(forKey: "password") as! String
    
        }
    
        func encode(with aCoder: NSCoder) {
            aCoder.encode(islogin, forKey: "islogin")
            aCoder.encode(type.rawValue, forKey: "type")
            aCoder.encode(username, forKey: "username")
            aCoder.encode(password, forKey: "password")
    
        }
    
    }
    

    When you call NSKeyedArchiver.archiveRootObject(::) it will call func encode(with aCoder: NSCoder) method and convert your NSObject to Data And when you try to Unarchive your object it will call init(coder aDecoder: NSCoder) method and convert Data to NSObject by using Key.

    But in Enum case you can not encode enum directly B'Coz it is User Define data type but rawValue is must be inbuilt data type like Int, String,Float.....So on. that's why when you try to encode enum you need to use rawValue

    I Hope you will get point.