NSKeyedArchiver - Unrecognized selector sent to instance error

ASN picture ASN · Dec 5, 2016 · Viewed 7k times · Source

I'm facing unrecognized selector sent to instance error while using NSKeyedArchiver.archivedData.

I was trying to store parse the JSON output to the custom class object and store it in NSUserDefaults on successful login. I wanted to use these details in other controllers to make some other POST calls. But while saving them in my LoginController I'm getting this error. Can some one help in resolving this.

My Class:

class UserDetails : NSObject,NSCoding {


    var token:String?
    var agentId: Int?
    var userId:Int?


    //to directly get values from JSON output

    init?(user: [String: Any]) {

        guard let token = user["token"] as? String,
            let agentId = user["agent_id"] as? Int,
            let userId = user["user_id"] as? Int
        else{
            return nil
        }


                self.token = token;
                self.agentId = agentId;
                self.userId = userId;
        }

    init(pToken:String,pAgentId:Int,pUserId:Int)
    {
        token = pToken;
        agentId = pAgentId;
        userId = pUserId;
    }

    //TO SAVE IN NSUSERDEFAULTS

    required init?(coder aDecoder: NSCoder){
        self.token = aDecoder.decodeObject(forKey: "token") as? String
        self.agentId = aDecoder.decodeObject(forKey: "agentId") as? Int
        self.userId = aDecoder.decodeObject(forKey: "userId") as? Int

        return self
    }

    public func encode(with aCoder: NSCoder) {
        aCoder.encode(token,forKey:"token")
        aCoder.encode(agentId,forKey:"agentId")
    }

}

And on successful login, I'm storing this details.

LoginViewController:

if let userDict = json["user"] as? [String:Any]
                        {
                            guard let userObject = UserDetails(user:userDict) else {
                                print("Failed to create user from dictionary")
                                return
                            } 
                            DispatchQueue.main.async {

                                self.saveUserItemToDefault(userObject: userObject);

                                self.dismiss(animated: true, completion: nil)
                                self.performSegue(withIdentifier: "loginSuccessIdentifier", sender: userObject)

                            }
                        }




 func saveUserItemToDefault(userObject:UserDetails) -> Void {
            let encodedToken = NSKeyedArchiver.archivedData(withRootObject: userObject.token) //error is thrown on the first archiver call
            let encodedAgentId = NSKeyedArchiver.archivedData(withRootObject: userObject.agentId)
            let encodedUserId = NSKeyedArchiver.archivedData(withRootObject: userObject.userId)

let encodedArray:[NSData] = [encodedToken as NSData,encodedAgentId as NSData,encodedUserId as NSData]

            self.prefs.set(encodedArray, forKey: "UserDetailsItem")
            self.prefs.synchronize()
        }

ERROR MESSAGE:

2016-12-05 18:08:57.917 ABCAPP[2800:183556] -[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x600000079f00
2016-12-05 18:08:57.920 ABCAPP[2800:183556] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x600000079f00'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000104b5e34b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x00000001045bf21e objc_exception_throw + 48
    2   CoreFoundation                      0x0000000104bcdf34 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
    3   CoreFoundation                      0x0000000104ae3c15 ___forwarding___ + 1013
    4   CoreFoundation                      0x0000000104ae3798 _CF_forwarding_prep_0 + 120
    5   Foundation                          0x00000001040f855c _encodeObject + 1263
    6   Foundation                          0x000000010412d29a +[NSKeyedArchiver archivedDataWithRootObject:] + 156
    7   ABCAPP                     0x0000000103fa8d4b _TFC15ABCAPP19LoginViewController21saveUserItemToDefaultfT10userObjectCS_11UserDetails_T_ + 235
    8   ABCAPP                     0x0000000103face3d _TFFFC15ABCAPP19LoginViewController10checkLoginFPs9AnyObject_T_U_FTGSqV10Foundation4Data_GSqCSo11URLResponse_GSqPs5Error___T_U_FT_T_ + 77
    9   ABCAPP                     0x0000000103f9d627 _TTRXFo___XFdCb___ + 39
    10  libdispatch.dylib                   0x0000000108112980 _dispatch_call_block_and_release + 12
    11  libdispatch.dylib                   0x000000010813c0cd _dispatch_client_callout + 8
    12  libdispatch.dylib                   0x000000010811c8d6 _dispatch_main_queue_callback_4CF + 406
    13  CoreFoundation                      0x0000000104b224f9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    14  CoreFoundation                      0x0000000104ae7f8d __CFRunLoopRun + 2205
    15  CoreFoundation                      0x0000000104ae7494 CFRunLoopRunSpecific + 420
    16  GraphicsServices                    0x000000010910da6f GSEventRunModal + 161
    17  UIKit                               0x0000000104f81f34 UIApplicationMain + 159
    18  ABCAPP                     0x0000000103faff2f main + 111
    19  libdyld.dylib                       0x000000010818868d start + 1
    20  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Answer

JPetric picture JPetric · Dec 5, 2016

The issue might be caused because you are trying to archive an optional and Optional doesn't have the encodeWithCoder method (hence the error message).

Try doing this:

public func encode(with aCoder: NSCoder) {
        if let token = token {
            aCoder.encode(token,forKey:"token")
        }
        if let agentId = agentId {
            aCoder.encode(agentId,forKey:"agentId")
        }
    }