Search code examples
iosmacoscore-dataicloud

Identifying iCloud coreData updates: good practice


I have applications (iOS and Mac) that uses iCloud and CoreData (same container). Each device may create or update data. When a device creates, or updates a managed object, other devices need to eventually perform a certain action (not UI related) related to the managed object.

So for example,

  • device 1 is offline,
  • Device 2 is online and changes a managed object.
  • Later, Device 1 is online: It must identify the created and updated managed objects to perform certain actions.

My question: can I rely on the notification system to achieve that ? (NSPersistentStoreCoordinatorStoresDidChangeNotification, and NSPersistentStoreDidImportUbiquitousContentChangesNotification)

Relying on notifications means that I must be certain that a notification will eventually reach my app on each device when the data has changed. In particular, is the data sync on the local store only executed when the app is running (thus hopefully ensuring that the notification will reach the app if it has registered soon enough) ?

Or should this type of requirement be implemented with my own mechanism for identifying modifications in the store? (which will complicate the model because each device will have to know that it has processed an update to a particular managed object)

Edit: Saw this sentence here:

Core Data imports changes persisted to iCloud from other peers after first-time setup and while your app is running.

That tells me that notifications are reliable for that.


Solution

  • Based on my experience the notifications are reliable. Changes from iCloud will only be synchronised while your app is running. That synchronisation will also only occur after you have added the corresponding persistent store. (ie. you have called addPersistentStoreWithType on your Persistent Store Coordinator).

    I always register for the notifications (code shown below) before adding my persistent store. In that way you can be certain that you will receive the relevant notifications.

    // Returns the persistent store coordinator for the application.
    // If the coordinator doesn't already exist, it is created and the application's store added to it.
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
        if (_persistentStoreCoordinator != nil) {
            return _persistentStoreCoordinator;
        }
    
        NSError *error = nil;
        _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    
        NSNotificationCenter* notificationCentre = [NSNotificationCenter defaultCenter];
    
        [notificationCentre addObserver:self
                               selector:@selector(CoreData_StoresWillChange:)
                                   name:NSPersistentStoreCoordinatorStoresWillChangeNotification
                                 object:coordinator];
        [notificationCentre addObserver:self
                               selector:@selector(CoreData_StoresDidChange:)
                                   name:NSPersistentStoreCoordinatorStoresDidChangeNotification
                                 object:coordinator];
        [notificationCentre addObserver:self
                               selector:@selector(CoreData_StoreDidImportUbiquitousContentChanges:)
                                   name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
                                 object:coordinator];
    
        NSMutableDictionary* workingOptions = [self.storeOptions mutableCopy];
    
        if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:workingOptions error:&error]) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    
        return _persistentStoreCoordinator;
    }