Question

I'm having trouble getting my UI to reflect external changes (made by another process) to an sqlite data store.

I have a fairly standard core data based NSArrayController / table view. My app gets notified that external changes have been made to the data, at which point I do a

[managedObjectContext reset]; // brute force, but data set is small

The problem is, doing this clears all data from the table. The array controller's arrangedObjects is also empty. I thought a subsequent

[arrayController fetch:nil];

might help, but it doesn't. Executing a fetch request on the managedObjectContext shows the data is present and updated, so the managedObjectContext knows about the changes.

Any clues as to how to "recover" from the reset? Or perhaps the reset approach is wrong altogether, in which case is there a better way to load the external changes?

Was it helpful?

Solution

I don't think two processes are supposed to work in the same Core Data database. It is probably better to let one process act as a server that owns (and opens) the database and let the other send it commands to make changes. I don't think Core Data was ever meant to support multiple processes talking to the same db.

OTHER TIPS

So I've been playing around with this exact situation, and I will not contradict the first answer-- you're probably not supposed to do this, and if you have to, maybe iCloud works. Don't use this code. I provide it to help others get to the point where they can discover all the issues I didn't fix, and move on.

That said, you can do what the original question was looking to do-- force the controller to reload from disk:

// Tear down bindings and context, create new context & rebind
[self.watcherAC unbind:@"managedObjectContext"];
[self saveAction:self]; // Optional, dependent on NSMergePolicy, etc
self.managedObjectContext = [[NSManagedObjectContext alloc] init];
self.managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
[self.managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
[self.watcherAC bind:@"managedObjectContext" toObject:self withKeyPath:@"managedObjectContext" options:nil];

// Force controller to refetch and rearrange
NSError* error;
[self.watcherAC fetchWithRequest:nil merge:NO error:&error];  // Immediate fetch
[self.watcherAC prepareContent];
[self.watcherAC rearrangeObjects];

That refreshes the tableView's content from the store on disk. (The tableView is bound to the watcherAC array controller)

I found that fetch: isn't immediate-- it's done the next time through the run loop for the application. So to have fetch / rearrange done in the right order, you need to use fetchWithRequest:

I'm not sure prepareContent: is needed, though it may have helped clear up faults in the controller content.

I have not been able to get it to restore the tableView selection, though that may be because I do this within a tableview delegate call, so the view's selection gets out of synch with the controller's selection no matter what hacks I try. Maybe this could work for someone, but I suggest trying to figure out how to not allocate a new MOC once your view has bindings to it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top