I am making an app that will store scores (kind of like a quiz app) - I will be playing around with core data and storing values to work out the best way to use core data. I know that if you start storing and fetching from core data and you then add/delete entities without migration, problems occur.
But, as I am only testing, I do not mind deleting the app of my device, and then reinstalling (which will cause me to lose data) - will this help me avoid the need of migrating (because when I download, it is seeing the new core data for the first time)
Thanks!
As you said "I do not mind deleting the app of my device, and then reinstalling (which will cause me to lose data)" so you dont need migration at all. Migration is needed when you have a already published app on appstore and you dont want to create a mess for people who have already installed your app.
Related
I'm using NSPersistentCloudKitContainer to synchronise data between different devices with CloudKit. It works perfectly well with a new project, however when I'm using it with old projects the old data which was added with NSPersistentContainer does not synchronise.
What I would like to achieve is to synchronise old data that was added with NSPersistentContainer after changing it to NSPersistentCloudKitContainer. Is it possible?
I've found a solution that works for my Core Data database - and mine is quite complex with multiple many-to-many relationships (A surgery/anaesthesia logbook app called Somnus)
I started by creating a new attribute for all my Core Data Entities called sentToCloud and setting it to FALSE by default in the Core Data model.
On the first load for an existing user:
Fetch request using the predicate "sentToCloud == FALSE" for each Entity type
Change sentToCloud to TRUE for each Object then save the MOC
This triggers NSPersistentCloudKitContainer to start syncing
I've done this in order of 'priority' that works for my database, assuming the iCloud sync sessions match the order in which Core Data is modified. In my testing this seems to be the case:
I first sync all child (or most child-like) Entities
Then sync their parents, and so on, up the tree
I sync the Object the user interacts with last, once everything else is in place so the relationships are intact and they don't think their data is borked while we wait for NSPersistentCloudKitContainer to reconnect all the relationships
I also leave any binary data (magically turned into a CKAsset behind-the-scenes) to last as it's not the most important part of my database
My database synced successfully from my iPad to iPhone and all relationships and binary data appear correct.
Now all I need is a way to tell the user when data is syncing (and/or some sort of progress) and for them to turn it off entirely.
ADDENDUM
So I tried this again, after resetting all data on the iCloud dashboard and deleting the apps on my iPhone & iPad.
Second time around it only synced some of the data. It seems like it still has a problem dealing with large sync requests (lots of .limitExceeded CKErrors in the console).
What's frustrating is that it's not clear if it's breaking up the requests to try again or not - I don't think it is. I've left it overnight and still no further syncing, only more .limitExceeded CKErrors.
Maybe this is why they don't want to sync existing data?
Personally, I think this is silly. Sometimes users will do a batch process on their data which would involve updating many thousands of Core Data objects in one action. If this is just going to get stuck with .limitExceeded CKErrors, NSPersistentCloudKitContainer isn't going to be a very good sync solution.
They need a better way of dealing with these errors (breaking up the requests into smaller requests), plus the ability to see what's going on (and perhaps present some UI to the user).
I really need this to work because as it stands, there is no way to synchronise many-to-many Core Data relationships using CloudKit.
I just hope that they're still working on this Class and improving it.
I m making an app with CoreData and iCloud integration. I went through the Apple Documentation to adapt my already working app to integrate iCloud synchronization.
Inserting objects and deleting seems to be working fine. When I delete the app and reinstall it on my phone all synchronized data are correctly restored.
My issue is when I modify an NSManagedObject. The context which I used to query CoreData to fetch my object does not detect any changes on my objects when I modify a field. Therefore the context is not saved. If I try to force saving context even when no changes are detected, nothing is saved.
I went through stack oververflow and found that the context must have a stalenessInterval set to 0.0. This did nothing to my app. Do you have any idea on what could be wrong ?
I noticed that the context carried by the NSManagedObject seems different than the one I used to fetch data. If I call save method on this context, nothing happened either.
I am completely lost, since I thought it would ba as easy as inserting and deleting objects.
Thanks for your help !
(ps: I code with Swift but even Objective C code is acceptable as answer :) )
I was actually trying to use two databases whereas I should have used configurations to separate entities saved to the cloud and those saved locally.
For those who wants more information on CoreData with iCloud i suggest to go through this video from Apple WWDC 2012 which helps a lot getting into this subject.
I have an app that reads wind readings at sites around the world. I decided to use iCloud and Core Data using a shoe-box style app.
The wind readings update hourly, after a few weeks of using the app I realised this was a bad idea as iCloud/Core Data just fills up with megabytes of transactions and restoring a device takes 10 minutes to download the store to a fresh device.
My solution to this was to use Core Data configurations so that the "sites" were stored in the iCloud store but the hourly changing "wind readings" which get deleted after 12 hours were stored in a local store. If it makes it easier to imagine, it works similar to RSS "sites" and "entries" which change hourly.
This all works great but I can't work out how to write migration code for the 2.0 version of my app. After reading how configurations work I had to remove the parent/child relationship between sites and wind readings and use fetch requests to link them up using a common siteIdentifier UUID.
Doing it this way I assume I cannot use light-weight migrations? Also loading up the versioned .momd model file just gives me the latest model so how do I get hold of the original model file to load up the store and do everything manually.
On the other hand, is this just too complicated and I would be better removing iCloud support or there is another way you'd recommend?
You should be able to use a lightweight migration in this situation.
The reason is, as far as your 'iCloud' configuration is concerned you are just deleting an entity and dropping a properties (i.e. dropping a table and a column). Automatic migration can handle that just fine.
However...
There is a catch. It won't copy the data you have to the 'local' configuration first. Therefore you will need to do that manually before the migration. Here are the basic steps:
Determine if this migration needs to occur.
Copy the sqlite file to "local.sqlite".
Stand up the iCloud configuration, this will delete the readings.
Stand up the local configuration, this will delete the sites.
Test, test, test again, and keep testing.
when dealing with CoreData, I've run into a few problems I'm trying to nip in the bud for future proofing the system out of the gate. The simple fact of the matter is that I've never done anything like this before (work with CoreData that is). While I've managed to figure out how to work with it in the app, I need to know a decent practice to signal an app between versions that default data needs to be refresh on first app launch.
So right now, in my AppDelegate, I setup my managed object context, and I perform a fetch request to see if there are any records at all in a particular table/entity. I only want this to happen on first launch so im not constantly rewriting the contents of the DB every app launch. Anyways, so it goes ahead and uses Object Models to handle inserting of data amongst the entities in question (theres a few)
Now, for this version of the app, it's going into the store without an API (thats a far future thing), but between versions released to the app store, we may have to update specific information within the entities (for example: prices), again I only want this refresh to happen on app launch. Also, the schema MIGHT change, Im not sure if or when, but I'd like to make sure this can accomodate that just in case.
I figured, versioning the coredata "Add Model Version" would do the trick, set the new db version as the active version, but when I launch the app in the simulator, nothing happens which tells me that the data inside is being retained.
Any help towards what it is that I should do to accomodate this would be appreciated. Thank you!
You should find the Core Data Model Versioning and Data Migration guide useful:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/Introduction.html
You'll also probably find Method for import initial data with coredata useful.
We're performing our first iOS app update, and also our first Core Data migration.
It seems more complicated than the examples of the Standard and Lightweight Core Data migrations i've seen online, but perhaps i'm missing something.
Our scenario is that we've updated the .xcdatamodel (simply added a new field), and also a lot of the reference data used in our app (stored in our Core Data database), but we need to retain some user data (stored in the same Core Data database).
I've added multiple versions of the model definition into our .xcdatamodelld file, and have played around with a Lightweight Core Data migration process (using a Mapping Model (an .xcmappingmodel file)), which successfully updates the model, but I can't see any obvious way in which it would allow us to import selected data (the user's data) from a previous version of the database into a new one bundled with the next version of the app (containing our updated reference data).
Any advice on how to approach this scenario would be very much appreciated.
Thanks in advance, Ted
Your users' database will be upgraded "in place". There won't be any migration or importing/exporting necessary. When the user runs the new version of your app, the existing database will be upgraded with the new fields. I'm not sure if this answers your question, but there won't be any "importing" going on.
In the end we've worked around this situation by putting the user's data into a plist file (there's a fairly limited amount of this), and retaining the Core Data database to use solely for reference data in the system, so it can be overwritten in future without worry.
A lightweight migration updates the data model on first run, and then a one off migration call creates and populates the user data plist file, renames the v1 core data persistent store *_migrated.sqlite, copies the v2 sqlite database from the bundle into the documents dir, then resets the MOM, and sets the MOM, MOC and Persistent Store to nil, so that the next time Core Data starts it uses the v2 sqlite database as its Persistent Store.
Phew. I hope this makes some sense to anyone reading it, feel free to ask for any other details, but it was honestly a lot simpler than it all sounds!