Where to store private important user data when the Documents directory is not an option? - iphone

My app is using iTunes file sharing which exposes everything in the Documents directory to the user, making it vulnerable to accidentally deletion or manipulation.
I spent hours in reading though these documents but it is a mess and I hope someone knows from experience. First, in one place they say that I should put these files in the Library directory.
In this technical Q & A Apple says that this is preserved. From my understanding this means that I can safely put important user data like sqlite3 database files in this directory. When the user updates to a new version, the content inside this directory will be preserved, it will survive and be available after the update:
applications can create their own
directories in
/Library/ and those
directories will be preserved in
backups and across updates
So /Library/ is preserved in backups and across updates.
For me with bad english this means: YES, the data will survive. It will not be lost when the user backs up. It will not be lost when the user updates. I looked up the word "preserved" in several dictionaries and I am sure it means "it will survive".
But then, there is this note in the iOS Application Programming Guide which tells something completely different! Here, they say about the Library directory:
<Application_Home>/Library/
You should not use this directory for user data files.
The contents of this directory (with the exception of the Caches
subdirectory) are backed up by iTunes.
Your application is generally
responsible for adding and removing
these files. It should also be able to
re-create these files as needed
because iTunes removes them during a
full restoration of the device.
"Should not use for user data files." (???)
But at the same time they admit it's backed up by iTunes. OK. So why shouldn't I put user data files into there, then?
/Library/Caches
Use this directory to write any application-specific support files
that you want to persist between
launches of the application or during
application updates. (...)
It should also be able to re-create
these files as needed because iTunes
removes them during a full restoration
of the device.
What?! I should put these files in Library/Caches. But this directory is not backed up by iTunes, as they said above. So this is only save for updates, but not for backup. And the data might be deleted anytime by the system.
Now this is completely confusing me. From what I understand I can choose between the evil and the devil: Data in /Library/ does not survive updates but is backed up by iTunes. Data in /Library/Caches does survive updates, but is not backed up by iTunes AND it might be deleted by the system (since it's a "Cache") anytime.
And on the other hand, the technical Q & A suggests putting this important user data in a custom subfolder in /Library/, for example /Library/PrivateDocuments.
In contrast to the iOS Application Programming Guide, the technical Q & A says: the entire /Library directory has always been preserved during updates and backups
So now, really, one of both documents MUST be wrong. But which one? What's the truth? Please, not speculation! I'm looking for answers from experience and I feel there is no way to figure this out except releasing an app and praying. Maybe someone wants to share his/her experience what really worked.

I've seen Library/Preferences (where NSUserDefaults are stored) be kept across restores, so I think most of Library is kept. The cache directories are probably excluded, though.
In general, just use the APIs to fetch paths and trust that iTunes will preserve them unless they're meant to represent temporary folders. That means you should use a subdirectory of your NSApplicationSupportDirectory named for your application:
NSArray * urls = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
NSAssert([urls count], #"Can't get app support directory");
NSURL * url = [urls objectAtIndex:0];
url = [url URLByAppendingPathComponent:#"MyAppName"];
In practice, this will end up being "Library/Application Support/MyAppName" in your sandbox, but you should use the API anyway to ensure this is kept future-proof.
(If you care about support for iOS 3 or 2, use the NSSearchPathForDirectoriesInDomains() function instead of the -URLsForDirectory:inDomains: method.)

The content inside Library folder (except cache) is backup by itunes.
What apple mean by "Should not use for user data files." (???) is that don't use this folder for data you want to be view in the File Sharing sytem via itunes.
So If you want the user to access the data via itunes write to /Document folder
If you want to hide the data from the user write to /Library folder

Why don't you try the keychain? If your data is not too extensive it can provide a quick way to store sensitive information
Keychain Documentation from Apple

Related

How to manage the iCloud Document of MAC App

The documents provided by APPLE did not make it clear to me. This may be my English level limit. I hope you can help me to get a better understanding of it.
I use the FileManager class to manage the files of icloud, including the methods of copyItem, moveItem, and removeItem. I directly deal with the files in the icloudDocument's address as an ordinary file. After matching with NSMetadataQuery, I compare the modification time and creation time of files, so I managed files, but I found it very bad, because I need to judge whether files need updating, uploading or deleting.
I later found that the FileManager class has Managing iCloud-Based Items, which includes the evictUbiquitousItem, startDownloadingUbiquitousItem, and other methods. It seems to be easy to manage, but it doesn't make me clear.
My problems are now:
which is the final file when the local file is not consistent with the icloud file? (there is no convenient method, automatic synchronization)
what should I do if the icloud does not exist, but when the local file exists? (delete it directly? Or is it necessary to judge?)
how do you know which files are downloaded to the local?

iOS App Rejected - Data Storage Guidelines

My iPhone app was rejected last week because of me not following iOS Data Storage Guidelines. My app basically searches for certain data and shows them to the user who can share them with others (Twitter, Email, etc) or save them to "Favorites" to view them later.
Earlier:
Earlier, I didn't follow any particular data strategy. My app was basically downloading all search data (images) into /Documents/ directory. Once the user marked a particular item as a "Favorite", those were saved into my custom made "Favorites" directory in /Documents/ path. My app doesn't use iCloud. Besides, I also forgot to purge downloaded search data (images) once the user has seen them and is no longer in the same view. I have since found out that the entire strategy was terrible and the reason for my app's rejection.
Now:
Now, since my app has been rejected, I have doubled down on fixing my app and making it as perfect as possible. The data strategy that I am following is very simple now:
a) All the downloaded search data (images and pList files for search results) are now created in /Library/Caches directory.
b) When the user adds an item to "Favorites", data associated with that item (image and text) are then saved into /Documents/ directory.
c) All the files in /Library/Caches and /Documents/ directories are marked with the attributed "Do not backup", since I don't want to take any space on iCloud.
d) All the search related data in /Library/Caches directory are immediately purged once the user moves to a different view and is not longer accessing the search results.
e) On app launch, I check to see if there are any residual files from previous session in /Library/Caches directory in case the app got terminated prematurely. If any residual files from previous search session are found, I delete them.
My question are:
A) Is the data storage strategy that I am following now acceptable?
B) Do I need to mark any search related files in /Library/caches/ with "Do not backup" attribute or is that unnecessary?
C) Should I mark the data related to user's favorite items in /Documents/ directory with "do not backup" attribute or is it okay if user's favorite items get backed up to iCloud?
A) This data strategy sounds much better with maybe one minor adjustment listed below.
B) You do not need to mark these files with the "Do not backup" attribute. Also, you do not even need to manually purge these files. These files are not backed up through iTunes or iCloud, and will only be cleared in certain extreme cases of low disk space.
C) The user's favorite items should certainly be backed up to iCloud. This would be a proper use of iCloud since it is intentionally for user generated content.

Newsstand App Storage

I have developed one app in which, monthly magazine issues are downloaded and stored inside the app Document directory.
But app have rejected app due to storing of magazine issue in document directory. My magazine file size is around 50 MB.
They mentioned below:
The iOS Data Storage Guidelines indicate that only content that the user creates using your app, e.g., documents, new files, edits, etc., may be stored in the /Documents directory - and backed up by iCloud.
Temporary files used by your app should only be stored in the /tmp directory; please remember to delete the files stored in this location when the user exits the app.
Data that can be recreated but must persist for proper functioning of your app - or because customers expect it to be available for offline use - should be marked with the "do not back up" attribute. For NSURL objects, add the NSURLIsExcludedFromBackupKey attribute to prevent the corresponding file from being backed up. For CFURLRef objects, use the corresponding kCFURLIsExcludedFromBackupKey attribute.
Any help appreciate.
Thanks.
Move your files to the Caches directory and you should be good to go.
I believe that if it is user generated content, there is no problem with storing it on the /Documents folder.
Since it is content that can be downloaded again, you have to set the NSURLIsExcludedFromBackupKey file attribute which prevents it from being backed up to iCloud.
Take a look at this question on setting the attribute: Use NSURLIsExcludedFromBackupKey without crashing on iOS 5.0

Application rejected because of not following iOS Data Storage Guidelines

We're storing data into Document directory of application and we got rejection of application. We've tried with "do not back up" attribute for storing data in current version with below code.
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL{
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
}
We've used it as per iOS Data Storage Guidelines.
In earlier version we've also tried with storing data in Private directory. But, we were not able to get approval of application.
Can you please give us some more description regarding why we are not able to get approval of application? or yet, we need any other changes in code regarding data storage? So, that we can get approval and we've new version of application on iTunes.
I think #Jasarien's comment is the right answer, but there was no further comm, and this question is relatively new, so I'll expand.
For others to see the rejection you get:
The iOS Data Storage Guidelines specify:
Only documents and other data that is user-generated, or that cannot otherwise be recreated by your application, should be stored in the /Documents directory and will be automatically backed up by iCloud.
Data that can be downloaded again or regenerated should be stored in the /Library/Caches directory. Examples of files you should put in the Caches directory include database cache files and downloadable content, such as that used by magazine, newspaper, and map applications.
Data that is used only temporarily should be stored in the /tmp directory. Although these files are not backed up to iCloud, remember to delete those files when you are done with them so that they do not continue to consume space on the user’s device.
Use the "do not back up" attribute for specifying files that should remain on device, even in low storage situations. Use this attribute with data that can be recreated but needs to persist even in low storage situations for proper functioning of your app or because customers expect it to be available during offline use. This attribute works on marked files regardless of what directory they are in, including the Documents directory. These files will not be purged and will not be included in the user's iCloud or iTunes backup. Because these files do use on-device storage space, your app is responsible for monitoring and purging these files periodically."
For example, only content that the user creates using your app, e.g., documents, new files, edits, etc., may be stored in the /Documents directory - and backed up by iCloud.
Temporary files used by your app should only be stored in the /tmp directory; please remember to delete the files stored in this location when the user exits the app.
Data that can be recreated but must persist for proper functioning of your app - or because customers expect it to be available for offline use - should be marked with the "do not back up" attribute. For more information, please see Technical Q&A 1719: How do I prevent files from being backed up to iCloud and iTunes?.
So I see why you would use "do not back up" and expect to be in compliance, but I think like #Jasarien said - They mean for you to move to more discrete directories like cache or temp.
In fact what would definitely pass the review is switching to Core Data and using the internal SQLite - but that's probably too much work.
So to wrap up - a post on how to save to caches or tmp -
Where to save files in iOS 5 applications?
(actually, maybe this was all a duplicate of that one... :-/)
GL!
Oded
-- Edit --
Another good post:
https://stackoverflow.com/questions/8164868/ios-data-storage-guidelines-available-since-when
-- Edit #2 --
And another good post:
iOS 5 does not allow to store downloaded data in Documents directory?
Guess I should've just pointed out the duplicates... :)
Have a look at this link http://developer.apple.com/library/ios/#qa/qa1719/_index.html#//apple_ref/doc/uid/DTS40011342
The code you are using is compatible for 5.0.1 and not 5.1 and later. You have to use Cache for <=5.0 . But the better solution would be to deploy for 5.1 and later instead of 5.0 because if you have large amounts of data, it is likely that the Cache will be cleared sooner of later. Hope it helps.

iOS 5 does not allow to store downloaded data in Documents directory?

I have made an application for my client by keeping target iOS as 4.
But since the application still not submitted to Apple store, my client is planning to upgrade it for iOS 5.0.
For this I read the guideline from Apple and found that "Only user-generated data or that cannot otherwise be recreated by your application, should be stored in the /Documents directory and rest should be stored to /Library/Caches directory"
In my application, I am using server model of in-app purchase for non-consumable product. For this I am storing all my downloaded data (which are basically books or magazines) to Documents directory. The Database is also present in the same directory which contains the details about the downloaded products.
My question is,
1. Should I have to change my code to store the downloaded data to Library/Caches directory instead of to the Documents directory?
2. Where should my database file be placed (to Documents or Caches)?
If I put it products in the Caches then I have to change the logic of retrieval also, since it is considered that if record is present in database, there is no need change the existence of the file and it directly opens it when user clicks on the magazine.
Kindly guide me on this issue.
Thanks in advance.
UPDATED:
I am updating this for those who are still not sure about this problem.
Using the guideline of accepted answer, I have implemented this in 2 of my applications and submitted them to Apple Store. Both were approved in review.
This may promote that the solution suggested in the accepted answer is correct.
Here are the trade-offs:
If you put your files in the Documents directory then they are backed up to iTunes or iCloud but if they are too big and it's possible to download the files again then Apple may reject your app
If you put your files in the Cache directory then they won't be backed up and Apple won't reject your app. However, when iOS 5 gets low on space it may delete all the files in there.
However, with iOS 5.0.1 there is a third option:
Put files in Documents but flag them so that they are not backed up. There's a technote (QA1719) on how to do this.
I think this is probably the best answer for you.
1. Should I have to change my code to store the downloaded data to Library/Caches directory instead of to the Documents directory? = Yes, you need to store the downloaded data to Library/Caches directory.
2. Where should my database file be placed (to Documents or Caches)? = You can keep the database in Documents directory.
One app I know was once rejected because of this. Storing downloadable data in Documents dir is not recommended. The logic behind it is that your data should not unnecessarily inflate the app directory. This app directory is backed up in iCloud, so inflated app directory will cause more data to be saved in iCloud.
If data can be downloaded again, like magazines, books pdf etc. Then keep it in Caches directory. Of course you can store pointers to data (like URLs etc) in the Documents directory so that the user can retrieve them later.
To answer your questions:
Yes, change your code to load DB from Documents and Data from Caches.
Keep database in Documents
You'll have to add code to check if a document in DB exists in Caches, if it doesn't your app should download it again.
On top of the suggestion that you should keep the data in cache directory, there is a concern that you should keep in mind when keeping the data into cache folder:
Whenever iOS feels the memory crunch it deletes all the cache and temp folder.
Problem is described here in detail
To protect these directory not to delete and keep everything for lifetime you should use the attribute that will keep the mentioned directory safe.
Solution is here:
I was looking for same query and I have got the solution .
According to the apple data storage documentation dev may stored the data in cache even user want to persist that data in low memory situation.develper just need to set Do not back up flag.
Use the "do not back up" attribute for specifying files that should remain on device,
even in low storage situations. Use this attribute with data that can be recreated but
needs to persist even in low storage situations for proper functioning of your app or
because customers expect it to be available during offline use.
This attribute works on marked files regardless of what directory they are in, including the Documents directory.
These files will not be purged and will not be included in the user's iCloud
or iTunes backup. Because these files do use on-device storage space, your app is
responsible for monitoring and purging these files periodically.
For more Information go through this link
Use Below Piece of code for setting the do not back up Flag.
import <sys/xattr.h>
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
} else { // iOS >= 5.1
NSError *error = nil;
[URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
return error == nil;
}
}
URL is the path of Data.
I have made an application for my client by keeping target iOS as 4.
But since the application still not submitted to Apple store, my
client is planning to upgrade it for iOS 5.0
Another option (if you are only going to support iOS 5) is to use NewsstandKit. This way only selected issues of the magazine will be deleted by iOS when low on "disk" space. My understanding is that iOS will delete selected issues based on the last time read and maybe the size.
If you don't use newsstand and your app is targeted, all the issues will be deleted.