Search code examples
iosswiftcore-datansuserdefaultsnsmanagedobject

Is it possible to save an NSManagedObject in NSUserDefaults?


I've having difficulty saving an NSManagedObject in userDefaults and I'd like to know a) should I be trying to do this or is this not an appropriate approach or b) if it is an appropriate approach, how can I get it to work?

I'm writing my app in Swift 2.3 and it has a few user default options, one of which is for a default "lift" (as in weightlifting, e.g. 'bench press', 'clean and jerk', 'incline bench press'). I'm actually converting them from an enum to a Core Data entity because every lift event that the user will be able to keep track of will be one of the available lifts types (for which I'll establish the appropriate relationship).

Here's the extension with the properties:

extension Lift {

    @NSManaged var liftName: String
    @NSManaged var type: NSSet

   }

and the Lift entity with the things Xcode is complaining about:

class Lift: NSManagedObject, NSCoding {
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(liftName, forKey: "liftName")
    } // Super.init isn't called on all paths before returning from initializer

required init(coder aDecoder: NSCoder) {

    // Initialization of immutable variable was never used, etc...
    let liftName = aDecoder.decodeObjectForKey("liftName") as! String

    }
  }

I've dealt with these types of errors before so my real concern is whether or not I'm headed down the wrong path.

I've read numerous threads tonight which have taught me that I'll need to encode an object (but not specifically an NSManagedObject) to save it then unencoded it when retrieving it and that my class must conform to NSCoding and what that protocol requires. But then I've seen threads that say NSManagedObjects should NOT be stored in userDefaults, but I don't know if that's true.

I've spent a few hours on this so before I go further, can/should this be done?


Solution

  • No, you should not store an NSManagedObject in NSUserDefaults. Core Data is an object persistence technology, so it doesn't make sense to try and persist an NSManagedObject in some other format.

    There are few alternatives you can use:

    1. You could simply store the name of the lift in your user defaults and then query for this to get the object back from Core Data. This may not work for you if lift names aren't unique
    2. You can add an identifier attribute to your Lift entity and store something like a UUID string in that attribute; You can then store the same string in UserDefaults. This will ensure one object is selected uniquely.
    3. You can add a new boolean attribute to your Lift entity default and again use a query to retrieve it; You would need to ensure you only set the value to true on one lift at a time.
    4. You can use managedObject.objectId.uriRepresentation to get a URL that you can store as a string and then use to retrieve the object later. This is probably the most complex solution and I would suggest you try one of the other options.