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.
Related
I have been having quite a time of figuring out the correct way to create a backup of a Core-Data backed .sqlite file and storing that backup, both locally and/or in iCloud (whatever the user prefers), for download, restore or sharing. Let me state up front that I am not talking about moving the persistent store to iCloud to be used by the app as its datasource. I am simply asking about creating backup files in this question.
In 2014, Apple changed their default journaling mode for Core Data SQLite stores to WAL.
https://developer.apple.com/library/content/qa/qa1809/_index.html
With that change, they recommended:
To safely back up and restore a Core Data SQLite store, you can do the
following:
Use the following method of NSPersistentStoreCoordinator class, rather
than file system APIs, to back up and restore the Core Data store:
- (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)error
Note that this is the option we recommend.
Prior to this, I had been using NSFileManager to create backups. With this recommendation, I believe that the correct way to create a backup locally is to add a new persistent store and then to migrate that persistent store to the desired backup location, using
the NSPersistentStoreCoordinator methods addPersistentStoreWithType:configuration:URL:options:error, and migratePersistentStore:toURL:options:withType:error, respectively.
My questions are two-fold:
I previously would zip my data to NSData before exporting it, and
would write the NSData directly to a file. My file extension would
be custom to my app, for sharing the zipped data via email or other
iOS sharing methods. With the
migratePersistentStore:toURL:options:withType:error method, I now
end up with a .sqlite file (and its corresponding WAL file, etc) in
the desired location, but I cannot figure out how to share this file
now. If I zip the file, won't I be in danger of losing the data I
worked hard to preserve by using
migratePersistentStore:toURL:options:withType:error in the first
place? I believe so, but I do want to enable my users to share/save their
backups vie email, etc, and I don't know how to best approach this now.
I am having a hard time understanding how
migratePersistentStore:toURL:options:withType:error can be used to
backup the file to iCloud. Much like the sharing example above, I
see that I can use
addPersistentStoreWithType:configuration:URL:options:error, and
migratePersistentStore:toURL:options:withType:error to get the
desired .sqlite copy locally, but if I then try to upload that local
file to iCloud, I fear I will lose the data I worked to preserve by
using migratePersistentStore:toURL:options:withType:error in the
first place. I have been trying to see if there is a way that I
could/should use
migratePersistentStore:toURL:options:withType:error to move the
newly created persistentStore directly to iCloud, but I haven't been
able to find any documentation on how to do that or if it should be
done at all. Is there a specific url I would need to use to indicate that the destination for the persistentStore is iCloud?
I would greatly appreciate any insights that can be shared regarding the answers to these questions.
ZIP should be safe way IMO since it has CRC data for data integrity validation.
You have to be careful though regarding shared CoreData store version. Suppose two users run different versions of the app and share the CoreData store between each other. CoreData doesn't support progressive migrations out of box. https://www.objc.io/issues/4-core-data/core-data-migration/
Maybe sharing a portion of data in JSON and re-creating CoreData entities from it would be safer and easier strategy for sharing data as opposed to sharing entire graph.
You can only copy file into iCloud container and share it across devices but you can't really use it directly from container or have incremental updates coming via iCloud. NSFileManager has setUbiquitous that allows to move file into iCloud container.
I'm working on an Application that uses Core Data with iCloud (with the great improvement given by iOS7). This application stores data to describe a task with this information:
name a NSString
date a NSDate
image a NSString which describes a path to the picture
The pictures could be stored in Documents or Library Directory (I have to decide which is the more convenient folder), by the way, in the same folder with a unique name.
Now I'd like to activate iCloud sync for the images too otherwise the experience of the user will be incomplete (I just sync DB data.. no images, a strange/wrong behaviour for an app).
I'm really confused by Apple Documentation. I can't find a way to understand exactly how iCloud data works for this kind of needs. I just want to sync every file of a folder as soon as they will be created. So my questions are:
Could you share some good resources to learn how to use iCloud for file sync
Have I to use UIDocument and other iCloud API? or is there something "automatic". Quite a new bye/stupid question, I know :(
Are there any problem using Core Data and Document based iCloud synch in the same app?
Note: I know that I can sync data just by adding file in the document folder and hoping that users activate document sync... but this is not what I want obviously.
It is pretty straight forward to use both Core Data transaction log synchronisation and file based synchronisation in the same app to achieve what you want to achieve.
So you would set up your Core Data stack to use iCloud options and synchronise data changes via iCloud. At the same time you would store your images in the Apps iCloud container so they get synchronised as well. Just remember you need to use a relative reference to the images in your Core Data fileURL because the full pathname will vary depending on the device the app is running on. So for example you would just store the image filename in Core Data and use a standard directory such as 'iCloudContainer/Documents/Images/' to store them. 'iCloudContainer' being the URL you get by calling the [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:] API.
I have uploaded sample Core Data apps that use iCloud for transaction log synchronisation (i.e. synchronising data in Core Data) and that use file synchronisation for storing Core Data backup files in iCloud which can then be accessed by any device. You should be able to use the same code for moving backup files to and from iCloud for your images. Just remember you have to trigger download of files from iCloud before you can use them either by doing a coordinated read or by initialising the download using NSFileManager.
http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/
http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/sample-apps-explanations/
Download and run the sample apps and use the built in Backup File Manager to make backup files and to copy them to and from iCloud using different devices. Then just use the same code when storing your image files.
Your App does have to handle things like the user changing iCloud account, logging into or out of iCloud etc. and them move the core data file and image files accordingly.
The only way to have this happen automatically is to create a binary data attribute in your model for the images. If you do this, you will probably want to check the external binary storage allowed option, so the photos end up stored as files and not in the database.
If you would rather store the photos external to your store, you will have to do more work. You will need to migrate the photos into the iCloud container yourself, using the NSFileManager methods, for example. You could also use a class like iCloud Access if you find that easier.
The downside to handling the photos yourself is that you can never be sure that they have all arrived on your device when the Core Data store syncs, so it could be one or more photos are missing, even though there are entries for them in the store. You would have to make sure your app could handle this scenario, perhaps showing a placeholder image until the real photo was accessible.
There are no issues using Core Data and Document syncing in one app. In fact, they are exactly the same under the covers. From iClouds point of view, they are all just files to be transferred.
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.
If I use the "Transformable" attribute in Core Data to store images, it is my understanding that Core Data may or may not store it in the persistent store based on file size. Normally I wouldn't care where it stored the image, but for this app I need to ship it with a pre-seeded database in case an internet connection is not found when the app is first launched. So I basically want to take a snapshot (including images) of the database and have it load the first time the app is launched.
My question is, if Core Data decides for whatever reason to not use the persistent store, will the images still get loaded when I load the pre-seeded database? Or will it be broken because the image(s) were stored in some magic area that no longer exists when the user installs on their own device?
Making an attribute transformable has nothing to do with using external storage. The Store in External Record File option is available for both binary attributes and transformables, but is not required for either.
If you have an attribute that is transformable and uses external record files, you're correct that Core Data decides whether to actually use an external file based on its own undocumented logic (but probably by checking the size). Those external files get saved in a subdirectory of the one where the data store is located. If your data store is named Foo.sqlite, then in the same directory where that file is found is a directory named .Foo_SUPPORT/_EXTERNAL_DATA/. You can deal with this in a couple of ways:
Copy the entire directory where Foo.sqlite lives, including dot files. This is preferred, because the path to the external references directory is undocumented and (in theory) could change. You'll get the external references but you don't need to hard-code the directory name.
Copy the directory directly, since you know where it is. Probably a less good idea, for reasons described above.
Or if you prefer, just don't use external references. They're not required for any attribute, and if you like you can just have all of your data in a monolithic SQLite file.
You can just tell core data to use external storage for your images, and make it not having to figure it out when to use it and use it all the time. You can find the option to assign a property to use external storage on the core data inspector of your property.
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).