One major issue was releasing the existing database correctly and then re-connecting. The last hurdle was to clear any existing references to any managed objects currently being viewed or cached.
After searching the net and some experimenting I finally have something that is working.
- (BOOL) updateDB { if (managedObjectContext != nil) { [managedObjectContext lock]; [managedObjectContext reset]; } if (persistentStore != nil) { NSError *error; if (![persistentStoreCoordinator removePersistentStore:persistentStore error:&error]) { NSLog(@"Unable to remove persistent store error %@, %@", error, [error userInfo]); return FALSE; } } if (managedObjectContext != nil) { [managedObjectContext unlock]; } if (persistentStore != nil) { [persistentStoreCoordinator release], persistentStoreCoordinator = nil; } if (managedObjectContext != nil) { [managedObjectContext release], managedObjectContext = nil; } if (managedObjectModel != nil) { [managedObjectModel release], managedObjectModel = nil; } [self replaceDB]; [self managedObjectContext]; [self clearDBReferences]; return TRUE; }
The managedObjectContext is initialised lazily, therefore is could be nil.
- (NSManagedObjectContext *) managedObjectContext { if (managedObjectContext != nil) { return managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { managedObjectContext = [[NSManagedObjectContext alloc] init]; [managedObjectContext setPersistentStoreCoordinator: coordinator]; } return managedObjectContext; }
The order of the messages are important to ensure the resources are released in the reverse order they were initialised.
The [self replaceDB] simple copies the new SQLite DB into place.
The [self managedObjectContext] simple forces the Lazily initialisation.
The last message races though all controllers requesting them to clear any references to managed objects.
I simple created a ReleaseResource protocol that has a clear method. If a controller implements this protocol then it can simple release any managed objects.
For example, I have a controller that subclasses UITableViewController.
-(void)clear { self.fetchedResultsController = nil; [self.tableView reloadData]; }
This code will obviously change depending on your application layout. This method races through the controllers looking for classes that implement the ReleaseResource protocol.
- (void) clearDBReferences { for (UIViewController *controller in tabBarController.viewControllers) { // for iPad if ([controller isKindOfClass:[UISplitViewController class]]) { NSLog(@"Clearing iPAD DB References"); for (UINavigationController *navController in ((UISplitViewController *) controller).viewControllers) { [navController popToRootViewControllerAnimated:FALSE]; for (UINavigationController *rootController in ((UINavigationController *) navController).viewControllers) { if ([rootController conformsToProtocol:@protocol(ReleaseResources)]) { [rootController performSelector:@selector(clear)]; } } } } // for iPhone if ([controller isKindOfClass:[UINavigationController class]]) { UINavigationController *navController = ((UINavigationController *) controller); NSLog(@"Clearing iPhone DB References"); [navController popToRootViewControllerAnimated:FALSE]; for (UINavigationController *rootController in ((UINavigationController *) navController).viewControllers) { if ([rootController conformsToProtocol:@protocol(ReleaseResources)]) { [rootController performSelector:@selector(clear)]; } } } } }
Thanks, Tate. This is exactly what I was looking for!
ReplyDeleteThis is really great! NIce work dude :)
ReplyDeleteHi Tate, thanks for the article!
ReplyDeleteI am basically doing the same in my app for some time now.
However, with increased code complexity I am running into issues: Sometimes I am missing some NSManagedObject instances in my cleaning process.
This makes me think that the whole pattern (hunting down NSManagedObjects all across your running app) might be not quite right.
What we are basically trying to do is propagating changes in our model down to the views – doing that kind of job is actually what Core Data is for, right?
In my perfect world, I would change the PersistentStore which would then post some notification causing the ManagedObjectContext to reconnect managed objects to the new store, deleting those who are not there anymore, updating others and creating new ones.
Then FetchedResultsControllers would be updated and could in turn propagate their changes to the view controllers via their delegates.
All these notification patterns are there – they just don't seem to work like that, maybe they are not made for that case.
I am not experienced enough with CoreData but I have the feeling we are missing something here.
What do you think about this?
Daniel
You are on the right track. I would create a protocol with two events. One to release and another to reload. Have your views/objects implement this protocol with require code to perform these operations. When these views are loaded have them register these events with NSNotificationCentre. Before you replace the database send a release notification and after send a reload.
ReplyDeleteMmorpg oyunları
ReplyDeleteINSTAGRAM TAKİPCİ SATİN AL
Tiktok Jeton Hilesi
Tiktok Jeton Hilesi
Sac ekimi antalya
İNSTAGRAM TAKİPCİ
instagram takipçi satın al
metin2 pvp serverlar
instagram takipçi satın al
maltepe mitsubishi klima servisi
ReplyDeletekadıköy mitsubishi klima servisi
kartal vestel klima servisi
ümraniye vestel klima servisi
kartal bosch klima servisi
ümraniye bosch klima servisi
beykoz daikin klima servisi
üsküdar daikin klima servisi
pendik toshiba klima servisi