0

I’ve shared the same .sqilte between two apps with App groups.

When I add a recording in App A and open App B (first launch), app B retrieve correctly data.

I would like synchronize data when I add a recording in App A and app B (already launched in backrgound), app B could retrieve data when It comes back into foreground.

This's why when App B comes back into foreground, I update Core Data Sack into applicationWillEnterForeground. Which way is correct ?

let directory = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("group.com.sl.sharedData");

        let url = directory?.URLByAppendingPathComponent("sharedData.sqlite")
        let store = self.persistentStoreCoordinator?.persistentStoreForURL(url!)
        var error : NSError?
        if false == self.persistentStoreCoordinator?.removePersistentStore(store!, error: &error)
        {
            println("error = \(error!.localizedDescription)")
            return
        }
        let options = [
            NSMigratePersistentStoresAutomaticallyOption: true,
            NSInferMappingModelAutomaticallyOption: true,
            // Adding the journalling mode recommended by apple
            NSSQLitePragmasOption: ["journal_mode": "DELETE"]
        ]
        var failureReason = "There was an error creating or loading the application's saved data."
        if self.persistentStoreCoordinator?.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options, error: &error) == nil {
            // Report any error we got.
            var dict = [String: AnyObject]()
            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()
        }
        _persistentStoreCoordinator = nil
        _managedObjectContext = nil
        let rootViewController = self.window!.rootViewController as ViewController
        rootViewController.context = self.managedObjectContext

Unfortunately, it doesn't work as I want. The retrieved data are dubbed each time, when I enter in applicationWillEnterForeground. Which way is correct ?

// Edit 2014/04/17 : Attempt with Mundi's solution

I have tried with NSManagedObjectContextObjectsDidChangeNotification

   func applicationWillEnterForeground(application: UIApplication) {

        NSNotificationCenter.defaultCenter().addObserver(
            self,
            selector: "mergeContextChangesForNotification:",
            name: NSManagedObjectContextObjectsDidChangeNotification,
            object: managedObjectContext)

        let rootViewController = self.window!.rootViewController as ViewController
        rootViewController.context = managedObjectContext
        }
    }

func mergeContextChangesForNotification(notification : NSNotification){
        let otherContext: NSManagedObjectContext = notification.object as NSManagedObjectContext

        if((otherContext != managedObjectContext) && (otherContext.persistentStoreCoordinator == managedObjectContext.persistentStoreCoordinator)){

            managedObjectContext.performBlockAndWait{ () -> Void in

                self.managedObjectContext.mergeChangesFromContextDidSaveNotification(notification)
            }
        }
    }

mergeContextChangesForNotification has been called but I have never entered in this condition : if otherContext != managedObjectContext) && (otherContext.persistentStoreCoordinator == managedObjectContext.persistentStoreCoordinator

Hobbes
  • 119
  • 9

1 Answers1

0

You should not set up your persistent store coordinator again if the app is already active. The standard lazy initialization used in the Xcode template is sufficient and preferable.

Instead, you might want to listen to the NSManagedObjectContextObjectsDidChangeNotification and update your UI as appropriate.

Mundi
  • 79,884
  • 17
  • 117
  • 140
  • I have edited my post because this is not readable in comments. Thx for your answer. – Hobbes Apr 17 '15 at 09:09
  • So which of the two conditions is not satisfied? You have to step through the code in the debugger and analyze why you are not getting the expected result. From my perspective, I have answered your question, you should accept this answer. For your other issue you might want to ask a new SOF question. – Mundi Apr 17 '15 at 10:22
  • The firs condition : otherContext != managedObjectContext`. I'm using different managed object context's that can't communicate via notifications. So posting a notification like NSManagedObjectContextObjectsDidChangeNotification doesn't work because NSNotificationCenter doesn't post the notification from my app A app to my App B as they are both different processes running in different memory spaces. – Hobbes Apr 17 '15 at 13:39
  • My issue is solved with this : ```func applicationWillEnterForeground(application: UIApplication) { for mo in managedObjectContext.registeredObjects { managedObjectContext.refreshObject(mo as NSManagedObject, mergeChanges: false) } }``` – Hobbes Apr 17 '15 at 13:40