Core Data with multiple objects, MagicalRecord init with 2 sqlite - ios

i want to be able to run 2 "databases" one for seed and one for userData
i'm using MagicalRecord but can't wrap my head around on how to accomplish this. so far i think i need a new NSManagedObjectContext for handling the 2nd database, i think. but how do i call it ?
also
how do i init 2 databases "momd" i googld all day today but either i'm searching for the wrong term or i don't know what. could someone point me in a direction ?
OR
should i just disband magical record and try it the hard way and figure out a way to have 2 sqlite's managed

It sounds like you really need to get a handle on Core Data itself prior to using MagicalRecord. Core Data can most certainly handle this scenario for you, however you will need to keep track of two different stacks, so two complete sets of NSManagedObjectContexts, NSPersistentStoreCoordinators, NSManagedObjectModels and NSPersistentStores.
If you want a "seed" data store , I suggest you do the following (besides really understanding how Core Data works):
Build your seed data store prior to application build
Seed your data store
Make a copy, and deploy that with your app in the app bundle. You'll likely need to reference it using [[NSBundle mainBundle] pathForResource:ofType:].
Copy this seed data store from your application bundle to your destination directory. DO NOT TRY TO MODIFY THE SEED DATA STORE DIRECTLY IN THE APP BUNDLE. Doing so will most likely not be possible anyway since modifying the app bundle is not allowed.
Once your seed data store is fully copied, load up the Core Data stack, through MagicalRecord or otherwise.
There is no sample code for this, as this is something you'll need to work out for yourself.

Related

How to create snapshot of CoreData state?

Background story
I am developing a big iOS app. This app works under specific assumptions. The main of them is that app should work offline with internal storage which is a snapshot of last synchronized state of data saved on server. I decided to use CoreData to handle this storage. Every time app launches I check if WiFi connection is enabled and then try to synchronize storage with server. The synchronization can take about 3 minutes because of size of data.
The synchronization process consists of several stages and in each of them I:
fetch some data from the server (XML)
deserialize it
save it in Core Data
Problem
Synchronization process can be interrupted for several reasons (internet connection, server down, user leaving application, etc). This may cause data to be out-of-sync.
Let's assume that synchronization process has 5 stages and it breaks after third. It results in 3/5 of data being updated in internal storage and the rest being out of sync. I can't allow it because data are strongly connected to each other (business logic).
Goal
I don't know if it is possible but I'm thinking about implementing one solution. On start of synchronization process I would like to create snapshot (some kind of copy) of current state of Core Date and during synchronization process work on it. When synchronization process completes with success then this snapshot could overwrite current CoreData state. When synchronization interrupts then snapshot can be simply aborted. My internal storage will be secured.
Questions
How to create CoreData snapshot?
How to work with CoreData snapshot?
How to overwrite CoreDate state with snapshot?
Thanks in advice for any help. Code examples, if it is possible, will be appreciated.
EDIT 1
The size of data is too big to handle it with multiple CoreData's contexts. During synchronization I am saving current context multiple times to cleanup memory. If I do not do it, the application will crash with memory error.
I think it should be resolved with multiple NSPersistentStoreCoordinators using for example this method: link. Unfortunately, I don't know how to implement this.
You should do exactly what you said. Just create class (lets call it SyncBuffer) with methods "load", "sync" and "save".
The "load" method should read all entities from CoreData and store it in class variables.
The "sync" method should make all the synchronisation using class variables.
Finally the "save" method should save all values from class variables to CoreData - here you can even remove all data from CoreData and save brand new values from SyncBuffer.
A CoreData stack is composed at its core by three components: A context (NSManagedObjectContext) a model (NSManagedObjectModel) and the store coordinator (NSPersistentStoreCoordinator/NSPersistentStore).
What you want is to have two different contexts, that shares the same model but use two different stores. The store itself will be of the same type (i.e. an SQLite db) but use a different source file.
At this page you can see some documentation about the stack:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/InitializingtheCoreDataStack.html#//apple_ref/doc/uid/TP40001075-CH4-SW1
The NSPersistentContainer is a convenience class to initialise the CoreData stack.
Take the example of the initialisation of a NSPersistentContainer from the link: you can have the exact same code to initialise it, twice, but with the only difference that the two NSPersistentContainer use a different .sqlite file: i.e. you can have two properties in your app delegate called managedObjectContextForUI and managedObjectContextForSyncing that loads different .sqlite files. Then in your program you can use the context from one store to get current data to show to the user and you can use the context that use the other store with a different .sqlite if you are doing sync operations. When the sync operations are finally done you can eventually swap the two files and after clearing and reloading the NSPersistentContainer (this might be tricky, because you will want to invalidate and reload all managed objects: you are switching to an entirely new context) you can then show the newly synced data to the user and start syncing again on a new .sqlite file.
The way I understand the problem is that you wish to be able download a large "object graph". It is however so large that it cannot be loaded at once in memory, so you would have to break it in chunks and then merge it locally into to Core data.
If that is the case, I think that's not trivial. I am not sure I can think of direct solution without understanding the object relations and even then it may be really overwhelming.
An overly simplistic solution may be to generate the sqlite file on the backend then download it in chunks; it seems ugly, but it serves to separate the business logic from the sync, i.e. the sqlite file becomes the transport layer. So, I think the essence to the solution would be to find a way to physically represent the data you are syncing in a format that allows for splitting it in chunks and that can afterwards be merged into a sqlite file (if you insist on using Core data).
Please also note that as far as I know Amazon (https://aws.amazon.com/appsync/) and Realm (https://realm.io/blog/introducing-realm-mobile-platform/) provide background sync of you local database, but those are paid services and you would have to be careful not be locked in (should not depend on their libs in your model layer, instead have a translation layer).

Storing CoreData to RackSpace

I am developing an app on xCode 5, iOS 7. I have some data stored in CoreData. My requirement is to upload that data to RackSpace. Whats the best way to do this?
Where can I find .sqlite file associated with CoreData?
The SQLite file is wherever you put it. There's no magic to it, you have to tell Core Data exactly where you want the file. You do this when you call addPersistentStoreWithType:configuration:URL:options:error:. The URL argument is the location of the SQLite file.
If you try and use the file directly, make sure that:
You shut down your Core Data stack completely before doing so, to make sure that all unsaved data has been flushed to disk. That means no managed objects, managed object contexts, or persistent store coordinators in memory anywhere.
Make sure to get the SQLite journal files. If your store file were named Foo.sqlite, they will be named Foo.sqlite-wal and Foo.sqlite-shm and will be located in the same directory. If you don't get these files, most or all of your data will be missing.
However simply uploading the file is not a good solution for syncing data. To sync data, you'd have to download a copy of the data, load that, and compare every object in the file with every object that's already on the phone. It's not impossible but it's definitely making things much more difficult than necessary. There are many options that can simplify the process, including full service providers like Parse, SDKs that let you use one of a variety of back ends like Ensembles.io, and others.

Migrating user data stored in sqlite to core data in app upgrade

I'm new to Stack Overflow and have been programming for only a year, so still a newbie with this stuff (i.e., please bear with me!). I'm upgrading an old app created in xcode 3 that uses an sqlite database to store user-generated data. The upgraded app needs to work with iCloud, so I've decided to switch to Core Data (because sqlite on its own can't be synced with iCloud). I have no problem implementing the Core Data structures but my problem is in how to allow users to retain their existing data.
I have already looked at topics along these lines: How to import a pre-existing sqlite file into Core Data? and Need To Populate Core Data From SQLite Database, and while I can create a utility app to import existing data, this is of no use because there is no existing data with the initial app bundle, the data is stored by the user.
I'd really appreciate any help I can get on this, have totally tied myself in a big knot over it! Maybe I'm better off avoiding core data altogether and finding another solution to save the sqlite data in iCloud?
Thanks in advance!
You can use core data. Create your core data model and stack, and your migration process consists of querying chucks of data from your sqlite database to insert them into the core data database.
Let's say that you have three tables in your sqlite. Person, Vehicle, and Property. You will create the equivalent entities in your core data mode, then you will have to query information from these tables to insert them into core data. You need to get familiar on how to insert data into a core data database, and how to use it on a multithreading environment (to avoid locking the application during the migration process).
Here's a few things to keep in mind:
Try to save in chunks. Do not load everything into memory, but also you must avoid making numerous save calls into your NSManagedObjectContext instance. Every save call into the context is IO. Balance IO and memory depending on your data usage.
Index the properties you have on your existing entities that can be indexed. This will help you build relationships (if any)
Ask the system for time before starting the migration. Use UIApplication's beginBackgroundTaskWithExpirationHandler: in order to be sure to have enough time from the system to continue the migration (in case the user sends the application to the background).
Do not bother cleaning the sqlite database. Delete the database file when you are done with it.
These are some of the things I can advice to you for now. If i think of more, I will edit this post. Best of luck.

From UIManagedDocument to traditional Core Data stack

I created a new App using UIManagedDocument. While on my devices everything is fine, I got a lot of bad ratings, because there are problems on other devices :(
After a lot of reading and testing, I decided to go back to the traditional Core Data stack.
But what is the best way to do this with an app, that is already in the app store?
How can I build this update? What should I take care of?
Thanks,
Stefan
I think you may be better off to determine your issues with UIManagedDocument and resolve them.
However, if you want to go to plain MOC, you only have a few things to worry about. The biggest is that the UIMD stores things in a file package, and depending on your options you may have to worry about change logs.
In the end, if you want a single sqlite file, and you want to reduce the possibility of confusion, you have a class that simply opens your UIManagedDocument, and fetches each object, then replicates it in the single sqlite file for your new MOC.
Now, you should not need a different object model, so you should not have any migration issues.
Then, just delete the file package that holds the UIManagedDocument, and only use your single file sqlite store.
Basically, on startup, you try to open the UIManagedDocument. If it opens, load every object and copy it into the new database. Then delete it.
From then, you should be good to go.
Note, however, that you may now experience some UI delays because all the database IO is happening on the main UI thread. To work around this, you may need to use a separate MOC, and coordinate changes via the normal COreData notification mechanisms. There are tons of documents, examples, and tutorials on that.
EDIT
Thanks for your answer. My problem with these issues is, that I'm not
able to reproduce them. All my Devices are working fine. But I got a
lot mails, about problems like this: - duplicate entries - no data
after stoping and restarting the app - some say, that the app works
fine for some days and stops working(no new data). These are all
strange things, that don't happen on my devices. So for me the best
way is to go back to plain MOC. My DB doesn't hold many user generated
data, all the data is loaded from a webservice, so it's no problem to
delete the data and start of using a new DB. – Urkman
Duplicate entries. That one sounds like the bug related to temporary/permanent IDs. There are lots of posts about that. Here is one: Core Data could not fullfil fault for object after obtainPermanantIDs
Not saving. Sounds like you are not using the right API for UIManagedDocument. You need to make sure to not save the MOC directly, and either use an undo manager or call updateChangeCount: to notify UIManagedDocument that it has dirty data that you want to be saved. Again, lots of posts about that as well. Search for updateChangeCount.
However, you know your app best, and it may just be better and easier to use plain Core Data.
Remember, if you are doing lots of imports from the web, to use a separate MOC, and have your main MOC watch for DidSave notifications to update itself with the newly imported data.
UIManagedDocument is a special kind of document, an UIDocument subclass, that stores its data using Core Data Framework. So it combines the power of document architecture and core data capabilities.
You can read more about document based architecture from Document Based App Programming Guide for iOS and I recommend WWDC2011 Storing Documents in iCloud using iOS5 session video. I also recommend Stanford CS193P: iPad and iPhone App Development (Fall 2011) Lecture 13.
What is created when you call saveToURL:forSaveOperation:completionHandler: is an implementation detail of UIManagedDocument and UIDocument and you should not really worry or depend on it. However in current implementation a folder containing an sqlite database file is being created.
No. All entities will be contained in a single database file also more generally called: a persistent store. It is possible to use more than one persistent store, but those are more advanced use cases and UIManagedDocument currently uses one.
UIManagedDocument's context refers to a NSManagedObjectContext from underlying Core Data Framework. UIManagedDocument actually operates two of those in parallel to spin off IO operations to a background thread. When it comes to the nature of a context itself here's a quote from Core Data Programming Guide:
You can think of a managed object context as an intelligent scratch pad. When you fetch objects from a persistent store, you bring temporary copies onto the scratch pad where they form an object graph (or a collection of object graphs). You can then modify those objects however you like. Unless you actually save those changes, however, the persistent store remains unaltered.
But it really is a good idea to take a look at the lectures and other material I posted above to get a general picture of the technologies used and their potential value to you as a developer in different situations.

Convert iOS app from NSCoding to Core Data

My app currently uses NSCoding to store persistent data, but I would like to make the switch to Core Data to take advantage of its integration with iCloud. The problem is that the app is currently live on the App Store, and I'm afraid that, once I make the change, the data on my current users' local stores will be lost.
In theory, I should be able to do the following:
Test for existence of NSCoding data
Convert data to Core Data format
Use Core Data for all future "saves"
... but I haven't found any documentation on making the conversion.
Any ideas? Or am I totally off somewhere?
Thanks
CoreData does some nice automated migration, but that's from different CoreData stores. In your case, you will have to write your own conversion code.
Leave the "old" classes around, and unarchive the "old" store if it is there. Then, just loop through the objects in the store, and create their CoreData equivalents. Save the CoreData, close it, then reload it as a check to make sure everything is identical. Then, delete the old storage file.
The only down side is that you have to keep old code around (at least enough to unarchive the old object formats).

Resources