I am working on a quizz app and I use realm database to store all data (questions, answers, isUserAnswered, isUserAnsweredRight, etc...).
I set up a bundle file to persist all of these data in a realm file when the user launches the app for the first time.
I would like to add new questions in by database at each update. How to persist these new questions without overriding previous data already stored in db ? It's a problem to override because I store for each question if the user has answered and if he answered right. I don't want my users to lose all their progress at each update.
This may or may not help but you could do one of a few things.
If your file contains primary keys for each object, as you are reading in the file, ignore the ones that match ones you already read in.
Another option is to version it - attach a version number to each object and only read in objects that are after the last read version.
Related
I am creating a core data app with preloaded data using an SQL file. I am able to create the preloaded data, insert that SQL file into the project, and there is no problem. When users open the app for the first time the pre-populated store is copied over to the default store.
However, I am thinking ahead that in future versions I will want continue to add to this database. I will want users to be able download the current version with the latest DB without erasing user-generated data or user-edits to data in the preloaded DB.
This is not a migration issue because the model has not changed. Basically, when a new version of the app is opened for the first time I want it to check for the presence of new objects in the pre-populated store and add them to the user store. Any suggestions are welcome.
Make your preloaded data include, for each object, the version where that object was first added to the preload file. Then add new data by
Look up the previous app version in user defaults. Compare it to the current version. If they're the same, stop, otherwise continue to the next step. (If there is no previous version number, continue to the next step).
Fetch all objects that were added more recently than the saved version number from step 1.
Add those objects to the user's persistent store.
Update the app version in user defaults so it'll be current next time.
You can do this check every time the app launches. You'll want to save a numeric version number in user defaults that will always increase in future versions of the app.
The simple way to record the version info in the preload file is just to add an extra field on each entity type. A more elegant way would be to create a new entity called something like VersionWhereAdded that includes a version number and a to-many relationship to objects added in that version.
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.
My app was rejected recently due to the fact that it installs a database within a directory which will be backed up to iCloud. As the database comes with a lot of prepopulated data and the app stores user generated data into the same file.
So mixing up user-generated-content with prepopulated data is not was Apple wants us to do.
So far so good.
Separate my database into two and mark the store file with the prepopulated data with NSURLIsExcludedFromBackupKey = YES.
But what happens if the user wants to modify the data in that store, because he found a failure and wish to modify it.
Or myself make an online update available which modifies values with that store.
How do I cope with that.
Do I have to delete the store file, create a new one (now with NSURLIsExcludedFromBackupKey = NO) or store the database under /tmp or /Library/caches right from the beginning and move it into /Application Support (which is backed up automatically) but with the threat that my database is being removed by the system for some reason what is the case for /Library/caches?
It is a bit annoying that Apple will not allow you to backup prepopulated data if your app is of the kind where you could actually change the prepopulated data in the app. If the prepopulated database is big, I can however understand that they don't want your app to waste the user´s iCloud space with information that is already in the AppStore.
Woody has a good idea on the approach, but I'm not sure Apple would look away from the fact that you are actually wasting just as much space if you copy the prepopulated data to the user-backed-up DB on app startup.
What about something like this:
A: DB with pre-populated data, not backed up
B: DB with user added
data, backed up
When user make changes to object in A, crete a new row in B that "overrides" the row in A, for example by using the same ID or by having a column in the DB that tells the app which object in A should be replaced by the new row in B.
Whenever you need to update your app, you will replace DB A with new content and that's it. This could lead to conflicts with the data that the user has changed. You will have to decide whether the user data is more important than the updated data, and how to handle these conflicts (for example by trying to keep them both).
If you need to change the structure of DB B in an update, for example if you need to add a column, you will have to include an update routine in your app that detects that the user is having an old DB version and write code to migrate the user data to the new database on first startup after the update.
When you startup, if the user database is unpopulated you could copy the data across from the pre-populated datatabse, and maybe give the user an option to reset defaults which does the same again?
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.
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.