Desktop iCloud Integration

So far in this chapter we’ve focused primarily on iOS; the reason is that the desktop implementation is actually a subset of the iOS implementation. There’s no UIManagedDocument on the desktop. As a result, we must use the traditional Core Data stack and add the options to the NSPersistentStoreCoordinator ourselves. Even if we’re using an NSPersistentDocument, we must still handle adding the options for the NSPersistentStoreCoordinator.

To build a new Core Data desktop application and implement iCloud data syncing, refer to Direct NSManagedObjectContext to iCloud for information, because the steps are identical. Further, to migrate an existing desktop application that uses a traditional Core Data stack, refer to Migrating an Existing Application, because that’s also identical.

If we’re using an NSPersistentDocument, things get a little interesting—not a lot but enough to merit attention. The first thing we need to do is to subclass NSPersistentDocument. The reason for this is that unlike with UIManagedDocument, there’s no way to pass in options to the NSPersistentStore when it’s being added to the NSPersistentStoreCoordinator. That’s the reason for subclassing.

DepartmentAndEmployees/MyDocument.m
 -​ (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL*)url
  ofType:(NSString*)fileType
  modelConfiguration:(NSString*)configuration
  storeOptions:(NSDictionary*)storeOptions
  error:(NSError**)error
 {
  NSFileManager *fileManager = [NSFileManager defaultManager];
  NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:nil];
 
 if​ (cloudURL) {
  NSString *pathComponent = [url lastPathComponent];
  cloudURL = [cloudURL URLByAppendingPathComponent:pathComponent];
 
  NSMutableDictionary *mutableOptions = [storeOptions mutableCopy];
  [mutableOptions setValue:[[NSBundle mainBundle] bundleIdentifier]
  forKey:NSPersistentStoreUbiquitousContentNameKey];
  [mutableOptions setValue:cloudURL
  forKey:NSPersistentStoreUbiquitousContentURLKey];
 
  storeOptions = mutableOptions;
  }
 
 return​ [super configurePersistentStoreCoordinatorForURL:url
  ofType:fileType
  modelConfiguration:configuration
  storeOptions:storeOptions
  error:error];
 }

In this override, we first check to see whether iCloud is enabled. If it is, we build our full iCloud URL and then add the two options required to link our persistent store with iCloud. Once the options dictionary has been updated, we return control to our super’s implementation.

In this example, we take the ‑lastPathComponent from the URL and use it as our unique sandbox within iCloud. Depending on the application’s design, this may not be unique enough, so we might want to consider storing a GUID inside the metadata of the NSPersistentStore and using that as the unique identifier within iCloud.

Once the initialization has been completed and linked to iCloud, all of the other behavior is the same between iOS and Mac OS X. We can listen for notifications about iCloud merging data into Core Data and handle those merges in the same way.