iOS: Update preloaded database with user-data mixed in - ios

I've looked all over for an answer, but it seems like I'm missing something obvious. I've made a rather complex Core Data app before, but the answer to this question has eluded me for the past few months.
Here's the problem:
1) I have about 20 entities in my Model.
2) Some of these entities have user-editable objects, others have pre-loaded data
3) I would like to know if it's possible to update the pre-loaded entities with each new app update.
I know I can do this the "manual" way by specifying each updated attribute, but this is way too cumbersome. I want to just update all the pre-loaded entities once the user opens an updated version of the app. I don't want to touch the user-data.
Thank you so much for your help!

You could have a version number field in your schema which you can use to associate a version number with each record. If it has a value, it's a preload. Then for the preload stuff just insert the new data when the app opens, and then ignore/delete the old. Seems simple enough.
UPDATE:
The other alternative I believe is to separate your preloaded data into an entirely different data store. I have an app wherein I do this by delivering my preloaded data via a custom SQLite file, and user data in a CoreData store. I can do this because my preloaded data is read-only, which saves me from needing to copy the SQLite file into the documents directory. What this means is that, at every update, the new data file automatically overwrites the old by virtue of the app installation. The user's data is maintained as it should be.
Of course if your preloaded data is not read-only, then there's no way around the need to write code. In this case there's not much I can do for you, not having any more details about your problem.

Related

How to replace sqlite file with the new one if I use core data?

I am currently working on the app that is going to use database to store items. The first thing that everybody say, when it comes to store data in iOS is Core Data.
But, after few days of looking through tutorials and docs, I have a big question.
Let me explain architecture a little bit more. So we have a backend, where you can add items, also, we have iOS and Android application. I am creating a Core Data model for our database.
What we want,is to check if there is update for database and download it. The problem is that we don't use JSON or XML, we are using the new sqlite file.
Since Core data creates three files for database, which are:
db.sqlite
db.sqlite-wal
db.sqlite-shm
Is core data able to replace "db.sqlite" with the new one, that is downloaded from server?
Thought the idea of replacing the database file instead of importing objects to it is very tempting it's highly discouraged to mess up with sqlite database created by CoreData. You should never touch it manually, when you do, you'll very likely end up with broken DB or messed up data.
So no, CoreDate is not able to replace underlaying sqlite file. You should instead import your data using CoreData stack, that's how it's designed. Creating JSON/XML service is the best way you can go.
BUT IN THEORY and in case you would be able to keep CD internal information stored in the db untouched, it should be possible to replace the sqlite file. If your database is read-only for users, it might work, but if users are able to create or modify records, forget about it right now.
First, you'd have to tear down all CoreData stacks (Managed Object Context, Persistent Store Coordinator, Managed Object Model) that might be using it before you replace it, replace the file and re-create CoreData stack(s).
db.sqlite is the main database file, the other two are temporary files, Write ahead log (wal) and Shared memory (smh), so you don't need these two.
Remember you never MUST NOT change the structure of the database, just data in it!!!
However, as stated in the beginning, I do not recommend this approach at all.

How do I perform Core Data Migration to an existing app, if all I'm changing is the SQL Db's content?

I've checked a lot of sites and answers and I can't find any solutions specific to my problem.
I don't need to change the schema for my Core data model, all I need is to modify (add some) content to the current backing SQL Database.
Any direction on this will be welcome. Thanks.
PS: I tried Apple docs and they were about as useful to me as sunshine on Mecury.
Also go easy please, I'm a beginner.
Thanks.
UPDATE;
To shed more light on my issue, my app works as thus. I have preloaded static information on the app that can't be changed by the user, each day has new content. Every month, I push an update with entirely new content specific to that month. However, when my app entered production, upon the update I pushed for this month, my users were complaining that they couldn't access the month's data. This led to me spamming them with Push notifications to have them delete the app and do a fresh install to access the new data.
How can I fix this issue? my schema stays the same, only the data changes.
If I understand correctly you want to pre-fill a Core Data database ?
If you don't care about pre-existing data on existing app, you can make an iPhone or Mac app with the same model, and let it generate the database, like explain here (Any way to pre populate core data?) it's also the way recommended in a really great book if you want to learn more about Core Data (http://pragprog.com/book/mzcd2/core-data).
Do not ever make SQL request directly, Core Data work in his own magic way.
Don't work on the SQLite-Database directly. Change all your Data through NSManagedObjectContext! To find a good strategy look up examples from Batch-Importing.
Update: You could actually have two PersistentStores (one with just static data (readonly) and the other one with user-generated data). You could interchange the readonly which you prefilled with a commandline util and downloaded from a server. You cannot have direct relationships between those two store though.
I would say that it depends on the amount of data in this prefilled store wether you should go this way or just use a plist and reference some string constants in your user data store. Try to do it with a plist as this is the simpler approach.

How to upgrade iOS Core Data model and data

I've got an iOS app which uses Core Data (SQLite on the backend). It only has one entity, 'Item'. There is a SQLite file bundled with the app, with hundreds of items pre-added, so when the user downloads the app from the App Store it already has the data.
The only entity has a BOOL favorite attribute which the user can alter, used -of course- to check if an item is among the user favorite items.
I'm planning to publish an update of the app with more items pre-built in the app bundle (a new SQLite file), but I want to keep the user favorites. As well, in this version my Core Data model will suffer a few modifications (I need some new properties in the 'Item' entity). The new set of items is a superset of the old items (an item in the old version of the app shall be in the new version, always).
I've been struggling with this a lot and I can't find a solution to this. I'm able to upgrade the data model introducing new properties into my entity while keeping the user favorites (performing a so-called lightweight migration, but then I'm not able to merge old and new items. On the other hand, I'm able to get the new pre-added items, but then the favorite-related data is discarded.
Any hint? Thank you all in advance
I finally managed to solve the problem.
I've got two NSPersistentStoreCoordinators, two NSManagedObjectContexts and two NSManagedObjectModels in my app delegate: one set to use in the application (the updated one) and another set pointing to the old store. In my app delegate didFinishLaunchingWithOptions: method I load all the user's favorites from the old store and save them into the new one. That's the only point in the app where I touch the old store.
Thank you all anyway!
I would suggest creating a second database with your new stuff in there, but without favorites. Then you pull favorites from your old database and insert them into your new one. Remove the old database and replace with the new one. That seems like the most straight-forward solution. There may be functionality built into Core Data for these situations, but chances are this is easier.

CoreData Update Database Leaving User Entries

First, Thank you for any help provided.
I have an iOS leveraging CoreData to retain various presentations, this data comes from a sqlite file and there is no server connection.
I will have to be able to provide App updates (via appstore), this update may add more data to the database.
The tricky part is that it can not simply overwrite the current database, there are a few user tables that I will not like touched.
Please provide any information I should consider when accomplishing this or any links are greatly appreciated.
Thank you.
Given your app has no server connection, you will have to rely on shipping data within the updated application itself. I would recommend using a plist file or define your own xml or json structure. You can then read this data to create/update core data nsmanagedobjects.
It looks like someone in the past was using plist->coredata on SO
Would you have relationships between user created data and shipped data?
If not, you might go the route of connecting two stored to the persistent store coordinator. The shipped store would be read-only. The store with user created data would be read-write. You can use this approach, too, if you have relationships between shipped and user-created objects, but it's a lot more complicated, since CoreData doesn't manage cross-store relationships for you, and you'll need to write your own logic (doable, but not straight forward).
If you need to have relationships between shipped and user-created objects, you can still ship a CoreData store. When the app launches for the first time (no user-created objects), you copy the store to the Documents folder and user this store to create your CoreData stack. User created objects will be added to this store. Once you have new 'shipped' objects (i.e. a new store in the app-bundle), you'll have to manually migrate that stores data into the store that the user has changed. You'll have to be able to find
(1) objects that need to be deleted
(2) objects that need to be updated (changed)
(3) objects that need to be added
If you mark your shipped objects with a special flag such that you can tell if it's a user created object or a shipped one, that would be doable. You also have to have some sort of ID to be able to tell which objects in the new store correspond to which ones in the existing (old) store.
You do not need to go the route of using plists. In fact, I'd recommend against it. You can easily open two stores at the same time. Either to use both stored, or just to migrate objects from one store to the other store.

How to split an iOS sqlite db?

I have an existing iOS app that uses core data for app data and user data. My problem is that updating app data is a nightmare (my first app, so I didn't do it ideally the first time). I would like to split the app data and user data into 2 separate sqlite dbs (or stores, correct me if my terminology is wrong).
Any tips would be appreciated.
Having two sqlite files is a good idea. The pain is splitting them now.
Create a new store that only exists in your app bundle. Make sure the data is unchanged from when you first released the app.
You are going to need to walk the "user" store and find all of the data that is identical to what exists in the "reference" store and delete it. If the user has changed that data then I would leave it and let the user sort out duplicates.
Once that is complete your app can resume normal function and load up both stores. I would set a flag somewhere so that you know this has been done and you don't run the check on every launch. The "user" store's metadata is a good place.
Note, this will need to be done before the user can "use" your app. This probably means changing your launch routines so that if a migration and filter is needed you tell the user what is going on.
I don't think having multiple persistent stores is the right solution. You can simply have separate entities within a single persistent store. Core Data will handle it properly.

Resources