The app I'm working on generally uses a single SQL store in Core Data to hold a working dataset for the app. However, there can be any number of small, separate stores which originated as either
In-app Purchased content, or
Exported subsets of the working dataset that may be reused from time to time.
These will always consist of a single sqlite file (WAL turned off). The In-App purchases can always be re-downloaded, but it would be possible for the exported data to be lost for good (since they might choose to permanently delete the data after it is exported).
Intuitively, since the exported data might not be possible to recreate, it should go in a subdirectory of the documents folder. But I'm not sure whether Apple would agree about that.
I have no idea where the downloaded purchased content should be saved, since technically, it can be re-downloaded at any time.
So, my question is, where in the iOS filesystem should I put these (iOS7 and beyond).
There is no official, public guidance on where content purchased via IAP should go on the filesystem. However, experience with Data Storage Guidelines feedback has indicated that:
NSDocumentsDirectory should only contain data created or edited by the user
(some) Non-user data can still be stored in NSDocumentsDirectory if it has the NSURLIsExcludedFromBackupKey attribute set. In general you should still try and avoid doing this.
In-App Purchase content is considered "restorable application data" and should be stored accordingly. The application support directory is one place where it could be stored.
If your exported data was exported by a user-initiated action and the data at that point "belongs" to the user, storing that exported data in the NSDocumentsDirectory should be fine. If you have any doubt, store it in the application support directory or caches directory. Be aware that in low space conditions the data may be purged by the system.
Related
The Situation
I have an app that stores a core data database in the documents directory. It seems to work well for the most part, except for the fact a few users (of a very large number) are complaining their data just 'disappeared'.
It's a carefully/well coded app, no weird errors or crashes coming from Core Data.
My Suspicion
iOS sometimes shows the word 'cleaning' beneath app icons when storage space is low. This cleans some directories to free up space.
Help!
Could this be the cause? If so, how can I stop this? Any light that can be shed on this would be much appreciated.
The documents directory is the recommended place to store a core data database and iOS will never "clean up" anything stored there.
Users can manually delete files in the Documents directory, by uninstalling the app or (if you've enabled it in info.plist) browsing their phone from in iTunes.
Most users do not expect their data to be destroyed when they uninstall an app (Macs and PCs would leave the data in place for example), so this is probably what's happening.
You should consider storing a second copy of the data on your server, or on the user's iCloud account. That way it won't be destroyed by an uninstall. If it's your server, then you can justify charging money for this feature (recurring revenue is good right?).
Backups to iTunes and iCloud will both include your database, so you can instruct users to restore to a recent backup to get their data back.
Also double check your code to see how it handles an out of disk space error when attempting to save changes to the database. Depending how you're using Core Data, this could go bad.
These days Core Data in iCloud or some other cloud solution is the best approach.
I know Apple will reject apps that backup data that can be reloaded from the app bundle. However, in the app I'm working on, we'll be providing some basic data that users will want to keep in the Core Data store along with the new data they have created and entered. So, users will use the "library" data we provide by integrating it with their own data as they work with the app.
My concern is whether Apple will require me to segregate these data in some way such that data from the bundle is not backed up to iCloud? Once the data are co-mingled, disaggregation would be complex and burden the app excessively.
So, my question is whether I have to concern myself with the co-mingling of user data with that data which is supplied in the app bundle?
TIA for any input on this as I've not found anything about it in the docs.
I had a similar situation in my app. It has sample data, but the sample data is designed to be edited by the user, and has metadata attached to it that is user specific. In other words, the data is mutable, and belonged with the rest of the user's personally created data.
At one point, the app was rejected. I first appealed to the reviewer, explaining that the data was mutable, and personal to the user — it would not be possible to reproduce the data purely from the app bundle. The reviewer would not budge, so I appealed, and they sided with the reviewer. Game over.
You may be able to get away with a small amount of data loaded from your bundle (<1MB). If you plan to include images or anything that will push up that amount, they will likely reject you.
I also heard from another developer rejected for including data downloaded from a web service in the user's store. Apple claimed that the data could be re-downloaded, which may be partially true, but ignores the fact that the web service was operated by a third party, and the downloaded data could be unshared at any time. It also ignores that the user can edit the downloaded data, and that the client app is attaching user-specific metadata that cannot be downloaded.
That developer was rejected as well. He eventually got the app through review by introducing a complex set of procedures to import the data: the user had to first download the data to a temporary holding area that was not backed up. They then had to explicitly import the data, and dismiss a wordy dialog warning that the imported data would contribute to their iCloud backup quota. Horrible. But that is apparently what Apple wants.
The rule is pretty mindless, in my view, and Apple seem to be completely oblivious to the implications in terms of user interface changes and drastic refactoring of an app's model. I can't imagine any engineers were involved in forming the rule, because they surely would have realized how much unnecessary complexity it would impose on developers. We can only hope they see reason at some point.
So my iOS app has just been rejected because it's storing too much non-user-created data in the SQLite database, which lives in the Documents folder.
The app basically involves a relatively large library of images -- around 60-or-so megabytes of them to start, and there are also in-app purchases which each add an additional 60-or-so mb of images. Furthermore, the user can add their own images to the library.
Right now everything (images and all) is stored in an SQLite database, which is generated when the app is first launched. As the user adds more images, or purchases image packs, those images are added to the database. To the user, all the images (user-generated or not) behave the same in the app.
But Apple won't allow this: I can't have all that data stored in the SQLite database in the Documents folder unless I set it specifically NOT to back up to iCloud, as it's all recreatable data.
But if I set it to not back up, then the user-generated data won't back up either, which I definitely don't want.
Any suggestions how I might "split up" the database, such that all the user-generated stuff can be backed up, but the included-or-purchased stuff isn't?
The reason you are being rejected is not following the Data Storage Guidelines. Data created or edited by the user belongs within NSDocumentsDirectory, while application data should be stored elsewhere (i.e., the Application Support directory). These requirements are a result of how iCloud backup and disk space purging work on iOS.
For a Core Data application, this means your persistent stores must be split into two different sets of files, in two different locations. This, in turn, ends up driving much of the application architecture and data model. To have relationships between the user data and application data, for instance, you must use two different managed object model configurations and the relationship must be a fetched property.
There is more detail on how to implement this in this answer.
An alternative for your specific case would be to save the images on the file system, in the caches directory or elsewhere. User images could exist in NSDocumentsDirectory while application images could exist in NSCachesDirectory. This would remove the images from Core Data and instead your model objects would have the path to the image on the file system. This would be a short term fix to get you through submission, and would probably work.
One option will be, storing your data to a server and calling is using web service. During first launch. Or as per requirement.
I've been having trouble getting an app submitted to the App Store. This is due to the fact that that database, which is updatable, is too large for the iCloud backup limitations. Most of the data in the db is static, but one table records the user's schedule for reviewing words (this is a vocabulary quiz).
As far as I can tell, I have two or three realistic options. The first is to put the whole database into the Library/Cache directory. This should be accepted, because it's not backed up to iCloud. However, there's no guarantee that it will be maintained during app updates, per this entry in "Make App Backups More Efficient" at this url:
http://developer.apple.com/library/IOs/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/PerformanceTuning/PerformanceTuning.html
Files Saved During App Updates
When a user downloads an app update, iTunes installs the update in a new app directory. It then moves the user’s data files from the old installation over to the new app directory before deleting the old installation. Files in the following directories are guaranteed to be preserved during the update process:
<Application_Home>/Documents
<Application_Home>/Library
Although files in other user directories may also be moved over, you should not rely on them being present after an update.
The second option is to put the data into the NSDocuments or NSLibrary directory, as mark it with the skipBackupFlag. However, one problem is this flag doesn't work for iOS 5.0 and previous per this entry in "How do I prevent files from being backed up to iCloud and iTunes?" at
https://developer.apple.com/library/ios/#qa/qa1719/_index.html
Important The new "do not back up" attribute will only be used by iOS 5.0.1 or later. On iOS 5.0 and earlier, applications will need to store their data in <Application_Home>/Library/Caches to avoid having it backed up. Since this attribute is ignored on older systems, you will need to insure your app complies with the iOS Data Storage Guidelines on all versions of iOS that your application supports
This means that even if I use the "skipBackupFlag", I'll still have the problem that the database is getting backed up to the cloud, I think.
So, the third option, which is pretty much of an ugly hack, is to split the database into two. Put the updatable part into the NSLibrary or NSDocuments directory, and leave the rest in application resources. This would have the small, updatable part stored on the cloud, and leave the rest in the app resources directory. The problem is that this splits the db for no good reason, and introduces possible performance issues with having two databases open at once.
So, my question is, is my interpretation of the rules correct? Am I going to have to go with option 3?
p.s. I noticed in my last post cited urls were edited to links without the url showing. How do I do this?
Have you considered using external file references as described in https://developer.apple.com/library/IOS/#releasenotes/DataManagement/RN-CoreData/_index.html . Specifically, refer to "setAllowsExternalBinaryDataStorage:" https://developer.apple.com/library/IOS/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSAttributeDescription_Class/reference.html#//apple_ref/occ/instm/NSAttributeDescription/setAllowsExternalBinaryDataStorage: . Pushing out large data into a separate file can help reduce database size .
My app was recently rejected from the app store for storing data in the Documents directory. I had moved it there because with the latest change, the db must now be writeable - it's no longer read-only.
In researching the solution, I've read that it's actually preferable to use NSLibraryDirectory. Is this so, and more importantly, will that address Apple's concerns? Their complaint is that the app lets the user download to much content (it doesn't let the user download any unless you count the db), and that it's storing "too much data" in the "incorrect location." The data is 8 mb, but could grow to about 10 or 12 mb max.
Actually its because of iCloud.
using iCloud, Application's document directory is synced to cloud and to other devices and hence Apple want developers to store only that data in document directory which they want to sync with iCloud.
I came to know this form one of my friends who work # Apple California and I'm not really sure if this material is on Apple's documentation.
I had this issue with an update to a suite of apps I develop the other week. The funny thing was that only five of the seven apps (exactly the same code base) were rejected.
I believe the issue in my case was duplicating assets from the .app bundle into ~/Documents.
My first attempt to comply with their new storage guidelines was to implement the do not backup switch on the files I was copying into ~/Documents. No deal with that so I had to change my implementation to not copy the data at all. The apps were promptly approved.
Your implementation is probably different but in my experience Apple no longer likes you copying things from the app bundle into ~/Documents, as it could be duplicating data unnecessarily (in their view).
They suggest copying into ~/Caches (or whatever it is), but this can be cleared in low storage situations and may not be right for your case either.
Hope that helps.
A product I wrote a year ago uses CoreData (with a SQLite data store). This database file is stored in ~/Library/Application Support//. This was approved by Apple without issue.
"Application Support" does not exist in ~/Library, so you will need to create it.
Documents is not a great place to store your database file for several reasons. Apple has their reasons, since they rejected your app. Another reason is that the Documents directory is accessible by the user (via iTunes), and unless the user deleting your database file is no big deal to the operation of your app, it is best to put it where they can not do anything with it directly and/or inadvertently.
You can still put those files in the Documents folder, you just have to give them an attribute that lets the file system know not to back them up to the iCloud
This is a great example of how to do so on different iOS versions