Sweeper Sweeper - 1 year ago 121
iOS Question

How to store a NSManagedObjectID persistently?

To avoid being an XY problem, here's some background:

My app allows users to create and save a lot of settings kinda like the Xcode's fonts and colors chooser:

enter image description here

This is because there are a lot of things that users can set. It would be easier to just tap on a saved setting instead of setting all those things again.

I used Core Data to store the settings the user saved. Each setting the user created is an instance of an

subclass. And now I need to store the selected setting persistently so that the user will have the same setting selected as before when the app reopens.

My first thought was to store the
subclass instance in
. But according to the docs, I can't store it unless I convert it to

A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.

Then I tried storing the
of the
subclass instance. I see that there is a
method that returns an
. So I thought this would work:

NSData(contentsOfURL: selectedOption!.objectID.URIRepresentation())

But the initializer failed somehow.

Now I realize that this is a stupid idea because even if I can convert it to
, I can't convert
back to

According to this question, the OP seems to be able to store the object id:

I store the selected theme objectID in NSUserDefaults so that when the app restarts, the selected theme will still be intact.

How can I do that?

Answer Source

NSUserDefaults has "convenience methods"

public func setURL(url: NSURL?, forKey defaultName: String)
public func URLForKey(defaultName: String) -> NSURL?

which allow to store and retrieve a NSURL like the one obtained by URIRepresentation(). The conversion to and from NSData is handled transparently. From the documentation:

When an NSURL is stored using -[NSUserDefaults setURL:forKey:], some adjustments are made:

  1. Any non-file URL is written by calling +[NSKeyedArchiver archivedDataWithRootObject:] using the NSURL instance as the root object.
  2. ...

When an NSURL is read using -[NSUserDefaults URLForKey:], the following logic is used:

  1. If the value for the key is an NSData, the NSData is used as the argument to +[NSKeyedUnarchiver unarchiveObjectWithData:]. If the NSData can be unarchived as an NSURL, the NSURL is returned otherwise nil is returned.
  2. ...

So saving the managed object ID is simply done as

                                             forKey: "selected")

and retrieving the object ID and the object for example like this:

if let url = NSUserDefaults.standardUserDefaults().URLForKey("selected"),
    let oid = context.persistentStoreCoordinator!.managedObjectIDForURIRepresentation(url),
    let object = try? context.existingObjectWithID(oid) {

    // ...

For alternative approaches of saving the selected settings, see the above comment.