Bogdan Bogdanov
Bogdan Bogdanov

Reputation: 992

Swift - Replace Core Data with iCloud Core Data

How to replace my exsisting Core Data with iCloud Core Data ? This is my persistentStoreCoordinator:

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
    // Create the coordinator and store
    var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

    var notificacionCenter: NSNotificationCenter = NSNotificationCenter.defaultCenter()
    notificacionCenter.addObserver(self, selector: "storesWillChange:", name:NSPersistentStoreCoordinatorStoresWillChangeNotification, object: coordinator)
    notificacionCenter.addObserver(self, selector: "storesDidChange:", name:NSPersistentStoreCoordinatorStoresDidChangeNotification, object: coordinator)
    notificacionCenter.addObserver(self, selector: "persistentStoreDidImportUbiquitousContentChanges:", name:NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: coordinator)

    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("MyApp.sqlite")
    var error: NSError? = nil
    var failureReason = "There was an error creating or loading the application's saved data."
    var options: NSDictionary = [NSMigratePersistentStoresAutomaticallyOption : NSNumber(bool: true), NSInferMappingModelAutomaticallyOption : NSNumber(bool: true),
        NSPersistentStoreUbiquitousContentNameKey : "iCloudStore"]
    if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options, error: &error) == nil {
        coordinator = nil
        // Report any error we got.
        let dict = NSMutableDictionary()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
        dict[NSLocalizedFailureReasonErrorKey] = failureReason
        dict[NSUnderlyingErrorKey] = error
        error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog("Unresolved error \(error), \(error!.userInfo)")
        abort()
    }

    return coordinator
}()

I add notifications and then what? How to replace it ?

Upvotes: 2

Views: 3656

Answers (1)

GoZoner
GoZoner

Reputation: 70155

You don't need to do anything to have the iCloud stored data replace the local stored data. That is, the local Core Data is updated with the iCloud-downloaded data and kept consistent thereafter, behind your back.

However, if you have displayed data in your UI then the 'old local data' might still be displayed when the 'new iCloud data' arrives. The Apple documentation at Using the SQLite Store with iCould describes how to handle the updates though the notifications. Summarizing that reference: in the handler for NSPersistentStoreCoordinatorStoresWillChangeNotification you save any pending changes if they exist otherwise you reset the managed object context and disable the user interface. Then in the NSPersistentStoreCoordinatorStoresDidChangeNotification handler your update your displayed (and other) data and reenable your UI.

This is what I've used for Core Data w/ iCloud. The storeOptions is the key point. For your Xcode target you need to enable the iCloud capability and ensure that you've selected 'iCloud Documents'.

{
  // ...

  lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
    // The persistent store coordinator for the application. This implementation
    // creates and return a coordinator, having added the store for the 
    // application to it. This property is optional since there are legitimate
    // error conditions that could cause the creation of the store to fail.
    // Create the coordinator and store
    var coordinator: NSPersistentStoreCoordinator =
      NSPersistentStoreCoordinator (managedObjectModel: self.managedObjectModel)

    var storeURL =
      self.applicationDocumentsDirectory
        .URLByAppendingPathComponent("iAppSwift.sqlite")

    var storeOptions =
      [NSPersistentStoreUbiquitousContentNameKey : "iAppSwiftStore"
      // NSPersistentStoreRebuildFromUbiquitousContentOption: @(true)
        ]

    // 
    self.registerCoordinatorForStoreNotifications (coordinator)

    var error : NSError? = nil
    var store : NSPersistentStore! =
      coordinator.addPersistentStoreWithType (NSSQLiteStoreType,
        configuration: nil,
        URL: storeURL,
        options: storeOptions,
        error: &error)

    if nil == store {
      // handle error
    }

    return coordinator
  }()

  func registerCoordinatorForStoreNotifications (coordinator : NSPersistentStoreCoordinator) {
    let nc : NSNotificationCenter = NSNotificationCenter.defaultCenter();

    nc.addObserver(self, selector: "handleStoresWillChange:",
      name: NSPersistentStoreCoordinatorStoresWillChangeNotification,
      object: coordinator)

    nc.addObserver(self, selector: "handleStoresDidChange:",
      name: NSPersistentStoreCoordinatorStoresDidChangeNotification,
      object: coordinator)

    nc.addObserver(self, selector: "handleStoresWillRemove:",
      name: NSPersistentStoreCoordinatorWillRemoveStoreNotification,
      object: coordinator)

    nc.addObserver(self, selector: "handleStoreChangedUbiquitousContent:",
      name: NSPersistentStoreDidImportUbiquitousContentChangesNotification,
      object: coordinator)
  }

  // ...
}

Upvotes: 5

Related Questions