I have a universal app written in Swift using xCode 6.3.2. It is currently very simple in that when I push a button a random number is generated and then stored using CoreData. This works perfectly until I implement iCloud. With iCloud enabled storing a new random number doesn't always propagate onto additional devices. It does most of the time, but not always.
I am testing using an iPad Air, iPhone 6 Plus and iPhone 4s
I am using the following three notification observers:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "persistentStoreDidChange", name: NSPersistentStoreCoordinatorStoresDidChangeNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "persistentStoreWillChange:", name: NSPersistentStoreCoordinatorStoresWillChangeNotification, object: managedContext.persistentStoreCoordinator)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "receiveiCloudChanges:", name: NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: managedContext.persistentStoreCoordinator)
and here is the function for the third one:
func receiveiCloudChanges(notification: NSNotification)
{
println("iCloud changes have occured")
dispatch_async(dispatch_get_main_queue())
{
self.activityIndicator.startAnimating()
self.updateLabel.text = "iCloud changes have occured"
self.managedContext.performBlockAndWait
{ () -> Void in
self.managedContext.mergeChangesFromContextDidSaveNotification(notification)
}
self.reloadTextViewAndTableView()
self.activityIndicator.stopAnimating()
}
}
I am not attempting to update the UI until the managedContext is finished with the merge, and I am performing everything on the main thread. I am really at a loss why the changes on one device are only displayed on the second or third one about 90-95% of the time.
As part of my trial and error, when I went to delete the app from my test devices and reinstall there is sometimes a message that an iCloud operation is pending, but it doesn't matter how long I wait, once the devices are out of sync they stay that way. Even when they are out of sync if I add another number or two those will still propagate to the other devices, but then I will invariably lose more data. It seems to work about 90% of the time.
I use the following to update the UI:
func reloadTextViewAndTableView()
{
let allPeopleFetch = NSFetchRequest(entityName: "Person")
var error : NSError?
let result = managedContext.executeFetchRequest(allPeopleFetch, error: &error) as! [Person]?
//Now reload the textView by grabbing every person in the DB and appending it to the textView
textView.text = ""
allPeople = managedContext.executeFetchRequest(allPeopleFetch, error: &error) as! [Person]
for dude in allPeople
{
textView.text = textView.text.stringByAppendingString(dude.name)
}
tableView.reloadData()
println("allPeople.count = \(allPeople.count)")
}
I am really at a stand still here. I am just not sure why it "usually" works...