Core-Data lightweight migration requires re-install - ios

My app under development uses core data.
When I add an optional attribute to an entity, I expected that automatic lightweight migration is done, because I use an NSPersistentCloudKitContainer, and all my NSPersistentStoreDescription have the default settings shouldMigrateStoreAutomatically = true and shouldInferMappingModelAutomatically = true.
After changing the xcdatamodeld file by adding an attribute and restarting the app with the old persistent store, no data is fetched, and no error is reported.
However when I re-install the app, everything works fine, because a new persistent store is filled with the iCloud data.
Maybe I can detect that the model has changed, delete the old persistent store, and setup a new one that is synced then with iCloud.
But it should also work without iCloud sync: I thought the old persistent store should be automatically migrated to the new model, i.e., the newly added attribute should be initialized with nil.
Is this a misunderstanding? Do I miss something? How to do the migration correctly?
PS: I have read this answer, but since my app is still under development, I thought I don't need different versions of the model, but could simply update it.

Related

I didn't migrate NSPersistentStore in new version, can I recover with an app update?

long story short, my Core Data schema was changed, and my app was submitted to the app store, which caused everybody who updated their app to crash. The crash is caused by a missing NSPersistentStore due to not migrating the data model properly.
I still see the .sqlite and associated database files in the documents directory, and if I downgrade to the older version everything works fine with all data. My question is, can I recover from this with an app update by somehow migrating the existing NSPersistentStore and adding it to the NSPersistentStoreCoordinator?
EDIT: so I didn't actually change my xcdatamodel myself, hence, "long story short". However, I did remove XMPPFramework from my project and I have a feeling this might have caused the core data problem.
EDIT:
I didn't make any changes directly to my data model, but I have pinpointed the problem. I was retrieving my NSManagedObjectModel using [NSManagedObjectModel mergedModelFromBundles:nil] which merges ALL data models present in the bundle. This included all data models that came with the XMPPFramework, and now that the framework has been removed, the NSManagedObjectModel that is passed into [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel] is different, thus causing the crash.
I resolved the problem by using FMDB to fetch the contents of the existing DB, then created a new sqlite file and pointed the persistent store coordinator to that new sqlite file. Then I just inserted all the existing data into the new database by looping through the existing data and creating the appropriate NSManagedObjects. I also stopped using mergedModelFromBundles to retrieve my data model and instead use initWithContentsOfURL.
Actually you might have updated xcdatamodel somehow after first version, And you didn't created a new xcdatamodel model for second version. So on second update it's crashing.
NOTE: After first version release, you have to create a second model version of xcdatamodel.
To create second model version of xcdatamodel -
1. first you have to select Model.xcdatamodeld -> Go to Editor on menu -> Add Model Version. Here you have to name a model version and based on which old model you want to create this new one.
Now whatever changes you want to make you should make on new model version xcdatamodel.
2. You can see on image, I've given a new name to my new model 'Model2.0', which is based on my previous 'Model'.
New model will work exactly like your old model, Additionally changes will be made on new model won't affect to your old model. So it won't crash your app after update.
3. You have to select your new 'Model2.0' as a default working model. For that please consider the below image.
4. Here you can see there is 2 model now. Please select 'Model.xcdatamodeld' a main model, and open it's 'File Inspector' on right side - as opened on above image.
5. There is 'Model Version' field on the right side, Which indicates the 'current' model selected on this project. Please select the new model 'Model2.0' for your updated version. Now you can run and it will work fine onwards.
NOTE: Please make sure now whatever changes you will make, you will do it on your new model 'Model2.0', So it won't conflict with your old model. You have to make new model each time, if you want to change configuration of xcdatamodel on updated app version.

Data migration and storeURL

I have app on app store and I set up storeURL to : Model 2.sqlite. It working good but now maybe 2 months later, I am working on new version app, I added new model version and set storeURL: Model.sqlite. But I cant migrate from old version(lightweight migration). When I set storeURL to : Model 2.sqlite and start my app, console show me Can't find model for source store. Where can be the problem? I dont wanna lose data from old version.
Thank you
The store URL is where your persistent store is put. It is logically nothing to do with the format of that store. Most apps will change their model several times but never once change the store's URL.
Your error suggests you've either removed the old version of your model from the build or, for some reason, declined to use a versioned model at all. If you were to open your current Xcode project now, would the old version of your model be in it? Is it located such that Core Data could be expected to know its relationship to the new?

Lightweight migration of existing core data database with iCloud to iOS 7

The WW2013 video on Core Data & iCloud mentioned that pre-iOS7 core data storage with iCloud can be migrated to the iOS7 way by specifying the NSPersistentStoreUbiquitousContentURLKey when setting up your persistent store coordinator.
Has anyone had any luck with this? With my persistent store, I had the SQLLite database in a .nosync folder and my log files in a different subdirectory. I've tried setting the NSPersistentStoreUbiquitousContentURLKey to point to each and I always get my entire database being over-written instead of everything migrating over.
I don't recall anything being said about migrating to iOS 7, I recall them indicating that to maintain compatibility with legacy apps where a custom path was specified for transaction logs you can continue using the NSPersistentStoreUbiquitousContentURLKey. This key should only be used to point to the log directory and nothing gets migrated when you use this, Core Data just uses the existing store and iCloud transaction logs.
To migrate it so that it uses the new defaults in iOS7 you would need to use the migratePersistentStore API to create a new store using a new file URL and only the NSPersistentStoreUbiquitousContentNameKey. Core Data will then automatically create the fallback and local (iCloud synced) store and iCloud transaction log files for you.
EDIT:
If anyone else is trying this an having problems try setting the store to use JOURNAL mode rather than the new default WAL mode. There seem to be some issues when doing certain migrations while using WAL mode. If anyone has figured out whether WAL mode has specific bugs please add a link here.

Core Data duplicate project for update of a submitted app

i have submitted an app on the app store that uses core data.
The problem is that i duplicated my project and then lost the first source code. If i update the app using the "duplicated" source code does it delete all core datas users may have stored? i know that if you change the file file-xcdatamodel without mapping the previous datas you will lose all you had stored, can i assume the duplicated project use the exact same file?
thanks in advance
In that case I think that, if you didn't modify your xcdatamodel, the data stored by user will keep during the upgrade. In order to be sure, you can install your own apo from App Store, save some data, update this app from Xcode with your new version and check if the stored data still are there.
If you've modify your xcdatamodel, you must perform a light or a heavy migration, depending on your canges.

iOS App SQLite database structure change

I am updating an old iOS app which used sqlite database. I changed the database structure adding columns to existing tables. Now, I am testing it on my device. If I clear my old app from iPad and then run this new updated version on it, it is working fine. But if I have the old version installed on ipad already and test this updated version, it is somehow using the old database instead of the one updated. Can some one help me why it is doing this?
My guess and to try and make a simple answer for you is this. It's likely you updated the database in the project file - which means when you run it, your new db will exist in the bundle. files in the bundle cannot be updated, so its common practice to copy the database out of the bundle and store it somewhere in the ios sandbox. I usually use the documents directory to keep it simple.
Most likely what is happening is that when you run it over a pervious install, it see's that the file is already copied over to the device so it does not touch it, however on new installs, it probably sees the database is missing so it copies it there and that is why on new installs it works fine but existing ones it does not.
Look in the app delegate or your root view controller for code that checks for the existing database and copies the database over if needed on startup.
If you need to update the database on existing installs, you would need to force the copy.
Beware though if you have data in the existing database not to overwrite it if its important. If important data is stored there, you have to either do a little shell game of getting the data and importing into the new database, or maybe a simpler way, is to run the database schema modification commands on the existing database so it is the same.
again, beware and make a copy of the local database file before you run those commands, just in case.
best of luck
In iOS, a SQLLite database is really just a file. When you used the old app, it created the schema in the database file. When you load the new app, the data remains, untouched. If you want to use the new schema, you will have to detect the old schema and update the existing data. I believe that there are documented ways to deal with this. Bryanmac's question reference seems to be a good place to start.
When you install a new version of your app, iOS actually installs it in a new directory and then copies the contents of the documents folder from the older version to the one in the newer version. If you want to just use your new db, the best way is to have this db renamed or stored in a different directory inside your app's document store.
Here's a relevant article on updating An sqlite CoreData backing store on iOS:
http://www.musicalgeometry.com/?p=1736

Resources