Backing up sqlite DB on iOS - ios

I would like to make backup copies of my app's main sqlite DB while my app is running.
1) I have read that it is safe to just copy the sqlite file if the DB has been checkpointed (at that point the wal file contains no important data). Does [managedContext save:] do that checkpointing, or is there something else I have to do? (ref -shm and -wal files in SQLite DB)
2) Is there any way, short of tearing down the whole core data stack, to be sure that core data doesn't try to write to the sqlite file while I'm copying it? My app does save frequently after any user input, and it would be nice if there was some way to force that to block for a second.

I have uploaded a sample app that provides backup and restore capabilities a number of different ways, including local backups, copy backups to and from iCloud, email backups, import from email, and file copy via iTunes. See link below for video demonstrating these capabilities and you can download the sample apps from the site.
http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/sample-apps-explanations/backup-files/
EDIT
It should be safe to create a new persistentStoreCoordinator with the same fileURL and to then use migratePersistentStore API without closing the App, save the main MOC first though. I always use JOURNAL=DELETE mode to ensure I just have to use a single file to deal with. If you are using WAL mode then you would need to backup all three files used by sqlite.

Regarding 2)
When I make backup, I close all mom's, moc's and persistent store. Then it's safe to make backup or restore. Also all views are waiting for events to release all coredata resources and bring them back when database is available again. It's good to have a singleton to manage coredata.

Related

Keeping a bundled realm up to date using REST

I have an app that uses a database of about 5000 entries.
This database is bundled in the app as a realm file.
I want to be able to update/add entries to this database regulary using REST and I think I have done it correctly - I just want to make sure.
This is how I have done it:
When the app is installed I copy the bundled database from the mainBundle to the Documents directory for read/write access. I then delete the database from the mainBundle.
When I update/add new entries to the database, they are pushed to the user using REST and inserted into the database located in the Documents directory.
When an update is released of the app, I make a check to see if the database already exists in the Documents folder - if it does I automatically remove the database in the mainBundle as it is not needed.
Am I on the right track with this? Is there a better way of doing it?
Appreciate any input!
Regards,
Erik
When I update/add new entries to the database, they are pushed to the user using REST and inserted into the database located in the Documents directory.
Technically, you can't push via REST. So I guess, you're either sending a background push notification to all installations or you're checking at application launch, whether there is a new version of the database available. That's at least what I would propose, but your requirements for getting new data out may vary.
When an update is released of the app, I make a check to see if the database already exists in the Documents folder - if it does I automatically remove the database in the mainBundle as it is not needed.
This doesn't work. The main bundle is the signed app bundle. If you would tamper the contents, that would prevent your app from launching. For that reason the access to it is limited by the OS to read-only. So this operation will always fail with an error. Instead you might properly just want to skip seeding the database from the main bundle.

Need a persistent place to store a backup of my Core Data store

I have an app that creates a backup of my Core Data store and stores it in the NSDocuments directory. When I try to restore from that directory (without restarting the app), everything is restored correctly. However, if I stop the app, restart it and try to do a restore, the directory is different and the restore uses an old version of the backup file (haven't a clue where it came from).
My question is: because I need to persist the latest backup file, where can I save it so it will be there when I need it? (possibly after many distinct executions of my app). I don't want to use iTunes, so I was thinking of possibly iCloud; I need something that is not accessable to the user so he/she can't accidently delete the backup file.
Library/ApplicationSupport will do what I need... (just in case someone else needs the same info). SD

My IOS App has been rejected- Data Storage Guidelines (2.23) I have 2 possible suspects

my app has been rejected due to iCloud Storage Restrictions. (2.23).
There are lots of questions for this situation, but i am still not sure why my app has been rejected.. Here are my suspects:
1- My app downloads pdf files and images for letting users see on "offline" mode when a user selects a row from a tableview. I've set my download folder as "Documents/privateDownloads" and set the folder (and files inside) url flags as "do not backup"
2- My app also has a 2Mb. "preload.json" file, which my app reads the file at first launch and preloads into the database only at first launch (with a progress hud showing the progress of importing data). I haven't set the "preload.json" file as "do not backup".I just drag dropped the file into "Supporting Files" group in Xcode.
My guess is the problem lies in the 2nd suspect, but i've also read that i should move the "privateDownloads" folder into "Application Support" Folder instead of Documents folder.
i always stored my offline files on nsurl cache for a very long time (technically forever), but this time i've decided to do like this.
thanks for reading and helping.
Edit: there is a note from app store for rejection reason:
"In particular, we found that on launch and/or content download, your
app stores 3.6MB"
When i control this issue, this is happening after my application "preloads" the data. But what i really don't get it is, i am storing this preloaded data in core data. So yes, i want this data to be backed up in iCloud?!
To solve the issue of your seed data being too large, you might split your Core Data stack in two separate stores - one which stores the user data and is backed up to iCloud. And a second one which stores the seeded data imported from your JSON. This store could then be excluded from iCloud backup via the "do not backup"-flags.
Another recommended way would be to ship a pre-populated store like described in this article on objc.io. Since you mentioned your preload.json is several MB, this would be even more desirable to pre-generate the store once than on every device on initial app startup. And you could apply the required file attributes for not backing it up more easily.
The issue won't have anything to do with your preload.json file. If that's included in your app distribution, it is part of the app and you don't need to do anything different with it.
I would suspect that the reviewer didn't notice you were setting the 'do not backup' flag on files you've added to the Documents/privateDownloads folder, or that you have a bug and the flag isn't being set at all. It is safer, if you're able, to store those kinds of files in a /Library/Caches sub directory. Then you don't need to worry about the flag.

sqlite db export from ios app cleanly

I need a solution for a feature in an app my company is building. It is an IOS app for iPhone and iPad and we support ios5 and above only.
The end result we need is for the user to tap a button inside the settings area that dumps the apps internal database cleanly, attaches it to an email for the user to then address to whoever they wish.
Attaching to an email is not an issue. What I am concerned about is if it is reasonable to think that exporting a copy of an sqlite database to an email as an attachment would leave the user with a usable copy of the database. My customer base is not good about doing backups but the data is nevertheless very important to them.
Will a hot export of an sqlite database be usable, i.e. is this supported, or will the database be corrupt sometimes/always?
Keep in mind that all this function has to do is make it so that a usable copy of the database gets off the device and stored safely offline so that I can then walk them through restoring the database by copying it back into the device using iExplorer or PhoneView.
In the future we plan to add a robust export and import feature, but for now we are looking for a solution that we can implement in a day or less.
Thanks in advance for anybodys input and gasp some objective-c code that would dump a clean copy of an sqlite database in such a way that the database will be usable and not corrupted.
You don't need to make a hot copy of the database. When the user chooses the backup feature of your app, close the database, copy the file, and then reopen the database. You can now attach the copied file to the email.
I have a feature in my app for doing just this. I've never had an issue with a corrupt database file. As long as there are no active transactions running, the sqlite file should be OK to copy, especially if there are no open handles.
Another option would be to use the sqlite3_backup_init and related functions to copy the database.

How can I ship my app with a pre-populated Core Data database?

My app uses Core Data and I want some default entries to be inside.
What's best practices of how to do that?
If you're already loading the pre-load data via a temporary routine for testing in your current code there's no reason you can't use the sqlite file it creates in the simulator's directory (no need to write a separate Mac app).
If you're not already filling that db you can still write an iOS app that does it. Odds are you've already written the methods for adding data to your store so you can use them to import the pre-load data as well.
Either way you'd grab the sqlite file from the simulator's directory and add it to your app's bundle; on first launch you'll copy it into the appropriate place in the app's directory before pointing Core Data to it. If it's really large the downside is that there will be a copy in the bundle and another on disk, but there's not much you can do about that other than grabbing the data over the network.
As others have suggested, if the amount of data is small you can just import it at first launch, using the methods you've already written for adding data as part of the normal app's workflow.
See the CoreDataBooks example, which has sample code for copying a database at first launch.
EDIT: I've created a Core Data framework (read about it here: http://bikepress.org/?p=1120) that includes this feature.
I would just create a database and put add it to my target so that Xcode copies it into the app bundle. At the first launch just copy it from the app bundle to eg. the documents directory or wherever your app expects the database.
There is Core Data Editor at the app store. Alternatively you could build your own simple mac app just for this particular DB and manage it from there. If the amount of default entries is small, then you're better off storing it in a plist or something and loading it into DB after the first launch.
In iOS 5, my app was rejected if I put a database file into resource bundle. So, I have to download the database from internet instead.

Resources