JDM
JDM

Reputation: 893

Saving Realm Object subclass in NSUserDefaults?

I'm introducing Realm into my swift project. I have a User class that I was saving an instance of into NSUserDefaults to keep track of the 1 logged in user.

After making User a subclass of Object, I get the following error when trying to unarchive (archiving seems to work OK):

Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (RLMStandalone_User) for key (root); the class may be defined in source code or a library that is not linked'

I have Realm installed as a Cocoapod, this are the relevant methods in the User clas

static var currentUser: User? {
    get {
        if let data = NSUserDefaults.standardUserDefaults().objectForKey(UserDefaultKeys.kUserData) as? NSData,
            let user = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? User {
            return user
        } else {
            return nil
        }
    }
    set {
        if let user = newValue {
            let data = NSKeyedArchiver.archivedDataWithRootObject(user)
            NSUserDefaults.standardUserDefaults().setObject(data, forKey: UserDefaultKeys.kUserData)
            NSUserDefaults.standardUserDefaults().synchronize()
        } else {
            NSUserDefaults.standardUserDefaults().removeObjectForKey(UserDefaultKeys.kUserData)
            NSUserDefaults.standardUserDefaults().synchronize()
        }
    }
}

// MARK: NSCoding

 convenience init?(coder decoder: NSCoder) {
    self.init()
    guard let firstName = decoder.decodeObjectForKey("firstName") as? String,
    let lastName = decoder.decodeObjectForKey("lastName") as? String,
    let email = decoder.decodeObjectForKey("email") as? String,
    let icloud = decoder.decodeObjectForKey("icloudUserID") as? String,
    let userType = decoder.decodeObjectForKey("userType") as? String
    else {
        return nil
    }

    self.firstName = firstName
    self.lastName = lastName
    self.email = email
    self.profilePic = decoder.decodeObjectForKey("profilePic") as? String
    self.icloudUserID = icloud
    self.userType = userType
    self.coverPhoto = decoder.decodeObjectForKey("coverPhoto") as? String
    self.facebookID = decoder.decodeObjectForKey("facebookID") as? String
    self.placeID = decoder.decodeObjectForKey("placeID") as? String
}

func encodeWithCoder(coder: NSCoder) {
    coder.encodeObject(self.firstName, forKey: "firstName")
    coder.encodeObject(self.lastName, forKey: "lastName")

    coder.encodeObject(self.icloudUserID, forKey: "icloudUserID")
    coder.encodeObject(self.userType, forKey: "userType")
    coder.encodeObject(email, forKey: "email")

    if let coverPhotoUrl = self.coverPhotoUrl {
        coder.encodeObject(coverPhotoUrl, forKey: "coverPhoto")
    }

    if let profilePicUrl = self.profilePicUrl {
        coder.encodeObject(profilePicUrl, forKey: "profilePic")
    }

    if let fbID = self.facebookID {
        coder.encodeObject(fbID, forKey: "facebookID")
    }

    if let placeID = self.placeID {
        coder.encodeObject(placeID, forKey: "placeID")
    }


}

Upvotes: 1

Views: 734

Answers (2)

TiM
TiM

Reputation: 15991

It's not possible to store a Realm Object in NSUserDefaults as (As you saw in that error message) they cannot be serialized or deserialized by the NSCoding protocol.

Instead, it might be better to add a primary key property to your User object (So you can use it to query that exact object from Realm), and store the primary key itself in NSUserDefaults instead.

Or better yet, instead of relying on NSUSerDefaults, it might be better to simply have a boolean property, isCurrent in your model, and using that to work out which user is the current one.

Upvotes: 3

matt.writes.code
matt.writes.code

Reputation: 674

You should keep your NSUserDefaults and your Realm data separate. They are two different methods of persistent data storage. If you've converted something to a Realm Object, you no longer need to (or should) try and put that into NSUserDefaults.

Upvotes: 1

Related Questions