1

I want to save my custom class object in userdefault. I'm trying to save it like this:

class func setModel<T: Hashable>(model: T, key: String) {
    let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: model)
    UserDefaults.standard.set(encodedData, forKey: key)
    UserDefaults.standard.synchronize()
}

but the app is crashing on the first line of this method with the error:

NSForwarding: warning: object 0x600003944000 of class 'DronesApp_Worker.WorkerProfileResponse' does not implement methodSignatureForSelector: -- trouble ahead Unrecognized selector -[DronesApp_Worker.WorkerProfileResponse replacementObjectForKeyedArchiver:]

My custom object class is given below:

class WorkerProfileResponse: Codable, Hashable, Mappable{

    static func == (lhs: WorkerProfileResponse, rhs: WorkerProfileResponse) -> Bool {
        return lhs.id == rhs.id
    }

    override var hash: Int{
        return self.id!
    }

    var id, is_logged_in, last_login, last_active: Int?
    var username, email, mobile_number: String?
    var categoryName: String?
    var userCategories: [SelectedCategory]?
    var userSubCategories: [SelectedSubCategory]?
    var biometricToken: String?
    var accessToken: AccessToken?
    var userStatus: UserStatus?
    var userProfile: UserProfile?

    required init(map: Map) {

    }

    func mapping(map: Map) {
        id <- map["id"]
        is_logged_in <- map["is_logged_in"]
        last_login <- map["last_login"]
        last_active <- map["last_active"]
        biometricToken <- map["biometricToken"]
        username <- map["username"]
        email <- map["email"]
        mobile_number <- map["mobile_number"]
        accessToken <- map["accessToken"]
        userStatus <- map["userStatus"]
        userCategories <- map["userCategories"]
        userSubCategories <- map["userSubCategories"]
        userProfile <- map["userProfile"]
    }
}
  • 1
    Don't use `NSKeyedArchiver`, especially since your type is already `Codable` conformant, simply use `PropertyListEncoder` or `JSONEncoder` as explained in [this](https://stackoverflow.com/a/49926513/4667835) answer. – Dávid Pásztor Apr 09 '20 at 08:37
  • I've changed this line: ```let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: model)``` to this: ```let encodedData: Data = try! JSONEncoder().encode(model)``` And now it is giving me error: *Argument type 'T' does not conform to expected type 'Encodable'* – Faraz Ahmed Khan Apr 09 '20 at 08:55
  • 1
    You need to change `T:Hashable` to `T:Encodable` in your `setModel` declaration. – Dávid Pásztor Apr 09 '20 at 08:58

2 Answers2

2

The error occurs because a subclass of NSObject is required.

As I already mentioned in your previous question to use NSKeyedArchiver the class must be a subclass of NSObject and must adopt (and implement) NSCoding.

Once again: NSKeyedArchiver (related to ObjC) has nothing to do with Codable (related to Swift).

vadian
  • 274,689
  • 30
  • 353
  • 361
1

Use JSONEncoder to save data to UserDefaults. Dummy code:

class YourClassName: Codable {
    //Your properties here

    func saveInPreference() {
        do {
            let jsonEncoder = JSONEncoder()
            UserDefaults.standard.set(try jsonEncoder.encode(Your object here), forKey: "Write UserDefaultKey here")
            UserDefaults.standard.synchronize()
        }
        catch {
            print(error.localizedDescription)
        }
    }
}

Hope that helps!

@Faraz A. Khan comment if you have any questions in the above piece of code.

Mohit Kumar
  • 2,898
  • 3
  • 21
  • 34