After making a rough version of my app, I am now looking to make the finalised version which is better and has many improvements. This involves changing the attributes in the entity holding the timers.
Having put the app on TestFlight already, some of the downloads will have data stored already. I am going to delete the current entity and make a new one. Will this cause any problems if data is already stored for the attributes within the entity that is going to be deleted?
IMPORTANT: I do not want to keep any of the data in the entity to delete and I want to delete it all, so when users update all their data will be gone (this is fine as I distributed it only to people I know e.g. family/friends), who have given some feedback.
Any help is much appreciated. Thanks in advance.
CoreData is very pedantic. Once a store has been created based on a data model, you cannot use it with a different model unless you do some kind of migration. Different in this case means almost any change to the model. Certainly changing the attributes for an entity, or adding a new entity, will be sufficient for CoreData to throw an exception if you try to open the existing store with the new model.
If you want to preserve the data in the existing store, you would have to do a migration, but since you do not want to preserve that data, it will be easier to delete the store when the new version of your app is first run, and let CoreData create a new store using the new model.
Related
I am currently doing some tests with Ensembles, specifically testing Core Data light migration.
My current configuration is as follow:
Device-A running my app with data model 1
Device-B running my app with data model 2
data model 2 is based on data model 1 with one additional string property, which is optional
My scenario is as follow:
At the beginning, running my app with data model 1 on both Device-A, and Device-B, everything synced fine using Ensembles (iCloud configuration)
On Device-B, install and run my updated app using data model 2
On Device-A, keep running my old app using data model 1, and add a new record
The result: the new record added on Device-A is uploaded to iCloud and then synced to device-B
My question: can I configure Ensembles to prevent it from uploading changes to iCloud in case that related data model is not the latest one? (i.e. in my case, Device-A uploads an object based on data model 1 while iCloud is already based on data model 2)
Thanks in advance!
UPDATE 1:
Drew, thank you very much for your answer. I definitely agree that uploads can't (and probably shouldn't) be prevented as Ensembles is a decentralised, peer-to-peer system.
In the ideal case, I would like that the device with the new data model will ignore data that is based on the old data model. (in a similar way to the existing behavior where the device with the old data model will ignore any data based on the new data model). Is that supported?
If not, please consider the following scenario as an example:
The old data model has an entity called 'Book' with two properties: title, and author (both fields are non optional)
The new data model has a new optional property called titleFirstLetter that should hold the first letter of the title field.
Currently, when Ensembles is not involved, I have full control when saving new NSManagedObject to the persistence store. Therefore, the updated code of my app which responsible for adding a new book, will make sure to extract the first letter from the title field and save it to the new titleFirstLetter property. (i.e. a book titled Catch-22 will have C in the titleFirstLetter property when book is saved).
In addition, when light migration occurs on the core data stack, I detect that, and perform a one-time procedure where I iterate all existing books in the database, and set the titleFirstLetter according to the title value. From this point and on, the database is consistent and valid, while the new code will ensure that future books added to the database will keep database valid.
Regarding Ensembles, if I don't have any control on old data coming from devices with older data model, how can I fill the new property of titleFirstLetter, if my code is never being called?
Thank you for your kind assistance!
You can't prevent it, no. Ensembles is a decentralised, peer-to-peer system. There is really no way for one device to know the current state of another device, so you couldn't prevent an upload.
The updated device should be capable of handling the old data from the other device. The device with the old model will ignore any data based on the new model, until it too is updated. Then it will merge all of that ignored data.
It is best to avoid migrations where possible, and stick to simple stuff like adding properties or entities, rather than tricky refactors. If you need to make a lot of changes, consider simply starting with a new ensemble (e.g. change the ensembles identifier).
I want to add a new fetch request template to a core data model. I know I could do it programmatically, but all the other fetch request templates are present in the core data editor and it makes sense to add the new one alongside them.
My question is, since this is part of a point release for an app that has been in the store for quite some time already, is there any chance this will break existing installs? Does it count as some kind of migration, or not? Obviously we will QA it, but I'd like to know the answer in advance, and googling has been fruitless so far.
It's not stated explicitly anywhere, but in the NSManagedObjectModel documentation, it says the following:
Changing Models
Since a model describes the structure of the data in a persistent store, changing any parts of a model that alters the schema renders it incompatible with (and so unable to open) the stores it previously created. If you change your schema, you therefore need to migrate the data in existing stores to new version (see Core Data Model Versioning and Data Migration Programming Guide). For example, if you add a new entity or a new attribute to an existing entity, you will not be able to open old stores; if you add a validation constraint or set a new default value for an attribute, you will be able to open old stores.
It doesn't explicitly mention fetch requests, but these don't have anything to do with the schema, so I think you'll be fine.
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.
I have a project on that uses core data and I had migration implemented for whenever I needed to make a small change to my model. However, in the past week I've had to do a complete overhaul of my model and the way it reacts that I can not migrate any of the data.
With this I was wondering if there was a way to check what version of the model I have in the device and perhaps, through code, delete it and completely create a new one from scratch. This may not be the most preferred way, but if anyone has any better solutions than I am open to suggestions.
Two reasonable options:
Use NSManagedObjectModel's usual versioning mechansim. Bump up the version of your new model. Core Data will automatically check to see whether a given store is compatible with one of the models in the app before it opens the store; if not, it'll give you an error when you try to add it. So if you don't provide the old model in your app, Core Data won't use any old stores. You can respond to the error by deleting the store. You can also check a store before adding it using -isConfiguration:compatibleWithStoreMetadata:. See Initiating the Migration Process for more.
Use a different name for any stores you create using the new model. It's not uncommon for an iOS app to use just one or two stores with specific names. You probably know the name you used for the store in previous versions of your app; switching to a different name gives you an easy way to know whether a store is compatible with the old or the new model.
If you have changed the properties so that some of the old properties don't exist in the new model, try using the respondsToSelctor: method to check if an entity responds to an old selector. If it does, you have the old model.
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.