Remove core data model on iOS app update - ios

My question is related to migration. I cannot do a lightweight migration as there are a lot of changes with attribute types and new relationships. I don't have time for a heavy weight migration since the code is not mine and needs faster delivery.
The workaround, which could work is when the app is upgraded, app should remove the old data and data model as the data is of no use and can be downloaded from the server again. On the app did finish launching, get the .db URL and just remove it and recreate it for the very first time after the upgrade?
After some research, all the methods are pointed to light weight migration. If there is a better way please assist.

-(void) removeCoreDataAndReset{
NSError *error;
NSPersistentStoreCoordinator *storeCoordinator = storeCordinator;
for (NSPersistentStore *store in storeCoordinator.persistentStores) {
[storeCoordinator removePersistentStore:store error:&error];
[[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:&error];
}
// Initialise managedobjectcontext , Store Coordinator etc
}
Reinitialise all after this method as you do in statrt

To remove the persistent store, you need to remove:
The actual persistent store file. This is located wherever you put it. You tell Core Data where it is when you call addPersistentStoreWithType:configuration:URL:options:error:, so if you're not sure, check there.
The journal files. These will have the same name as the persistent store file, but with -wal and -shm added to the end. This is very important, because in most cases nearly all of the existing data is in these files.
You can remove files with methods on NSFileManager. If you do this, do it before accessing Core Data in any way, i.e. before creating any Core Data objects of any kind.

Related

CoreData: How to correctly use migratePersistentStore to create a backup copy

I'm really struggling with this. I'm trying to create a backup of my active core data base. According to Apple the best option is not to use the File Manager but the method migratePersistentStore. However I don't really understand this. I have my PersistentStoreCoordinator in my AppDelegate. So if I'm migrating the persistent store my coordinator will lose it after successfully moving it correctly? So the store is now just at the new location but not at the old anymore? So do you have any example program code for this of how my app still could keep running with the original copy?
Or can't i just copy all files using the filemanager with the same prefix instead of migrating?! So much easier...
You can create a separate NSPersistentStoreCoordinator for migration only, and continue using your regular one for CoreData stack. Also you can use NSMigrationManager for migration:
NSMigrationManager* manager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel
destinationModel:targetModel];
BOOL migratedSuccessfully = [manager migrateStoreFromURL:sourceStoreURL
type:type
options:nil
withMappingModel:mappingModel
toDestinationURL:destinationStoreURL
destinationType:type
destinationOptions:nil
error:error];
Also I'm not sure you can migrate when your DB is opened, probably you'll need to lock it or something.

Configuration for RestKit in-memory Core Data store

I need to split my Core Data persistent storage (managed by RestKit) into two parts. One part should persist only in memory and not be saved to disk, and the other part should be saved. Usually it is done by adding configurations to Core Data object model and creating two stores for each configuration. But RestKit's RKManagedObjectStore method - (NSPersistentStore )addInMemoryPersistentStore:(NSError *)error; doesn't take configuration name and adds persistent store with configuration nil:
- (NSPersistentStore *)addInMemoryPersistentStore:(NSError **)error
{
if (! self.persistentStoreCoordinator) [self createPersistentStoreCoordinator];
return [self.persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:error];
}
According to Core Data documentation, this prevents from using any configurations in persistent store coordinator.
I can reload this method and make it use configuration, but first I want to ask:
Are there any reasons for me to not to do this? There must be reasons why addInMemoryPersistentStore looks like it looks. May be someone had tried to make the same thing as I'm going to do and found that it doesn't work?
I would say that you should create your own version of the method which takes a configuration parameter. I don't think that you're missing anything, I just think that if RestKit was to offer support for 100% of the Core Data configuration API out of the box then there would be a lot of code to maintain and very few people would benefit from all of the extra effort.
Your best option is to subclass and add the method you want, calling super as appropriate, and then instantiate that subclass and pass it when you are configuring your Core Data stack (managed object store).

Is it possible to save a NSManagedObjectModel?

I have the following requirement: create and populate a SQLite database with data from a .xml file, this file can have a different structure any time so I cannot create the NSManagedObjectModel with Xcode, it must be at runtime. I've successfully created a NSManagedObjectModel programmatically, created the persistent store and populated the sqlite file with data from the .xml . However, the next time I use the app the persistent store is not compatible with the NSManagedObjectModel (I don't want to recreate the Model every time I run the app, just the first time). Is there any way to save the model I created programmatically and load it the next time it is needed? All I can see in the examples are models being loaded from the NSBundle.
Is there any way to save the model I created programmatically and load it the next time it is needed?
Yes. NSManagedObjectModel conforms to NSCoding, which means that you can easily convert it to/from NSData, and saving and reading NSData is easy.
To save a model:
NSString *modelPath = // path where you want to save
NSData *modelData = [NSKeyedArchiver archivedDataWithRootObject:self.managedObjectModel];
[modelData writeToFile:modelPath atomically:YES];
To read a saved model:
if ([[NSFileManager defaultManager] fileExistsAtPath:modelPath]) {
NSData *savedModelData = [NSData dataWithContentsOfFile:modelPath];
NSManagedObjectModel *savedModel = [NSKeyedUnarchiver unarchiveObjectWithData:savedModelData];
}
I'm not sure if you are saying that the data in the xml file is changing each time or what. It sounds like you are referring to the data, not the data model. I can't answer specifically, but I would take the approach as follows.
If the data in the xml file is structured the same or close to the same each time, I would create a data model to match that.
Then I would write some sort of parser class that would read the xml and parse it into the Core Data data store according to you "ManagedObjectModel" or data model.
I have seen the error you are talking about when you change the datastore outside of Core Data. You need to let Core Data handle all the reading and writing to the data store or else Core Data will tell you basically that "Your Persistent Store was created or altered by something other than your ManagedObjectModel". I think this is what is happening.
I know I am not using the terminology exactly as Core Data puts it, but Core Data is confusing and I'm trying to convey the message and understanding.
I would also look in to using MagicalRecord. It Drastically makes Core Data easier to work with and there is a great tutorial on www.raywenderlich.com which you can find Here
I really hope this helps you out some. If not, please post some sample code or maybe an example of that xml you are referring to.
Good Luck

Core data : Clear data which is added with PersistentStoreWithType:NSInMemoryStoreType

I am using core data for the first time in one of my application. There is a requirement like for particular scenario I do not want to save data in data base. For this I read the apple doc and come up with PersistentStoreWithType:NSInMemoryStoreType. And it works well and those object resides in memory till we kill it.
But now I am facing some issues in it. I want to clear that data at some point and I want to download it again so how can I clear all the data from store which are added for persistent store of type "NSInMemoryStoreType"?
Is there any way I can remove it from memory without killing application?
You can delete all objects.
for (NSManagedObject *object in fetchedObjects) {
[self.managedObjectContext deleteObject:object];
}
Or if you have never "saved":
[self.managedObjectContext rollback];

How to add SQLite database to iOS (CoreData) app?

I have an iPhone app that uses CoreData.
I want to add a pre-populated SQLite database to it. The database has 1 table (geographic locations, about 50K of them).. cities.sql
I am a bit puzzled what would be the best way to add this database?
I saw several approaches (such as locating the app folder in /Users/user/Library/... ) but my external database does not really have the same structure as apps database (no "User" table etc..).
I just want to treat this cities.sqlite as some data source.. I don't mind merging it with the apps appname.sqlite if necessary...
I am also using RestKit to manage the CoreData / API integration.
Question - how do I add this cities.sqlite to the app so I can ship the app with the pre-populated data from that database ?
Ok,
my approach to create a pre-populated db is to create a dummy app that has the goal to only populate the db you want to create. This let me to do some testing on the db without using the real app. Obviously, models should be the same.
Then, you can put it to the main bundle of your real app. Once executed, the app will check if the db exists in your document folder (for example), if not, it will copy the db from the bundle to the document folder.
NSString *storePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: #"yourStore.sqlite"];
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle]
pathForResource:#"yourStore" ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
In Core Data Import, you can find what I mean (for the second part, but you are free to follow also the approach to populate the db).
Hope that helps.
Edit
I'll try to explain better.
You create a dummy project.
Here you can use the model (with its entities) you created in the main app. Just copy it i your dummy project.
Create some code to populate the sql store through NSManagedObjectContext stuff.
The result will consist in a sql store already populated. You don't need to touch any sql store (only through Core Data).
Move to the application folder directory into the App Simulator, copy the store and put it in your main application bundle.
EDIT: If you are working with plain SQLite database, you will need to migrate the data to CoreData-friendly persistent store. To do this you can use sqlite library to read the data. You can do this in app directly, or you write some ulitity app for this. After you get the SQLite Core Data persistent store, follow my original post:
With Core Data you can have multiple SQLite stores combined into one context. Just add two persistent stores to your NSPersistentStoreCoordinator.
[coordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:mainSQLiteURL // URL for your main DB
options:nil
error:nil];
[coordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:citiesSQLiteURL // URL for the additional DB
options:nil
error:nil];
After this, when you create NSFetchRequest with entity City (I don't know your entity name) it will return cities from both SQLite files.
In case you want to just search one of the stores, you can set -setAffectedStores: of your fetch request. Also, when you insert new City object, you will need to specify the persistent store by calling -assignObject:toPersistentStore: on your context. Otherwise it will get confused about where to save the new city.
Or just merge those two stores to a single file.

Resources