UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: NSKeyedUnarchiver.unarchivedObject(ofClass:) throwing error

Forums > Swift

I am trying to save the user details to preference as below

static var userLoginResponse : LoginModel? {
        get {
            if let data = UserDefaults.standard.data(forKey: "userLoginResponse"){
                do{
                    if let respData = try NSKeyedUnarchiver.unarchivedObject(ofClass: LoginModel.self, from: data){
                        return respData
                    }

                }catch{
                    print("error in retriving data \(error.localizedDescription)")
                    return nil
                }
            }
            return nil
        }
        set {
            if let value = newValue{
                do{
                    let archiveData = try NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: false)
                    UserDefaults.standard.set(archiveData, forKey: "userLoginResponse")
                    print("Userdata saved success")
                }catch{
                    print("error in saving data : \(error.localizedDescription)")
                    UserDefaults.standard.set(nil, forKey: "userLoginResponse")
                }
            }
        }
    }

But the NSKeyedUnarchiver.unarchivedObject(ofClass:) is throwing error. "The data couldn’t be read because it isn’t in the correct format"


class LoginModel: EVObject {    
    var status = ""
    var message = ""
    var token = ""
    var data = LoginDataModel()
}

class LoginDataModel: EVObject {
    var first_name = ""
    var last_name = ""
    var email = ""
    var userid = ""
    var client_id = ""
    var access_level = ""
    var user_type = ""
    var dashboard_url = "https://google.com"
}

And EVObject is NSCoding

Can anyone please suggest solution for this.

2      

Hi! I think the problems in that:

The methods of the NSKeyedArchiver and NSKeyedUnarchiver classes work with Property List values (NSNumber, NSString, NSData, etc.). If we want to archive our own data types, we must covert them to Property List values.

2      

This is for decoding:

if let data = UserDefaults.standard.data(forKey: "userLoginResponse"){
    if let respData = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSData.self, from: data) as Data? {
                          let decoder = PropertyListDecoder()
                          if let result = try? decoder.decode(LoginModel.self, from: respData)  {
                          return result
                      }
                  }
              }

this is for encoding:

let encoder = PropertyListEncoder()
if let data = try? encoder.encode(value) {
    if let archiveData = try? NSKeyedArchiver.archivedData(withRootObject: data, requiringSecureCoding: false) {
      UserDefaults.standard.set(archiveData, forKey: "userLoginResponse")
    }
}

sorry for any typos though :) but the idea is like that. Just modify for your do catch block

2      

Thank you for helping me. I changed the code as below.

static var userLoginResponse : LoginModel? {
        get {
            if let data = UserDefaults.standard.data(forKey: "userLoginResponse"){
                do{
                    if let respData = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSData.self, from: data) as? Data{
                        return LoginModel(data: respData)
                    }else{
                        return nil
                    }
                }catch{
                    return nil
                }
            }
            return nil
        }
        set {
            if let value = newValue?.toJsonData() {
                do{
                    let data = try NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: false)
                    UserDefaults.standard.setValue(data, forKey: "userLoginResponse")
                }catch{
                    UserDefaults.standard.setValue(nil, forKey: "userLoginResponse")
                }
            } else {
                UserDefaults.standard.setValue(nil, forKey: "userLoginResponse")
            }
        }
    }

It works as expected. Hope this is correct.

2      

If you are using just UserDefaults and there is not specific purpose for you to use NSKeyedArchiver and NSKeyedUnarchiver. I suppose you can even boil down to something like this:

static var userLoginResponse: LoginModel? {
    get {
        if let data = UserDefaults.standard.data(forKey: "userLoginResponse") as Data? {
            if let respData = try?  JSONDecoder().decode(LoginModel.self, from: data) {
                return respData
            }
        }
        return nil
    }
    set {
        if let newValue {
            if let encoded = try? JSONEncoder().encode(newValue) {
                UserDefaults.standard.set(encoded, forKey: "userLoginResponse")  
            } else {
                UserDefaults.standard.setValue(nil, forKey: "userLoginResponse")
            }
        }
    }
}

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.