Issues writing files on iOS - ios

I'm fighting with the following error NSCocoaErrorDomain 513 reported by a very small number of users:
Unable to create directory at path /var/mobile/Containers/Data/Application/EBE2C5D8-5AEC-4D62-9393-B19CAD598FE5/Documents/documents/FF2F88FB-2C07-4FA3-988E-58AD5C21F659/9A02F8A0-74EB-4ED6-81B6-4F40653856D3.
Error: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “9A02F8A0-74EB-4ED6-81B6-4F40653856D3” in the folder “FF2F88FB-2C07-4FA3-988E-58AD5C21F659”."
UserInfo={
NSFilePath=/var/mobile/Containers/Data/Application/EBE2C5D8-5AEC-4D62-9393-B19CAD598FE5/Documents/documents/FF2F88FB-2C07-4FA3-988E-58AD5C21F659/9A02F8A0-74EB-4ED6-81B6-4F40653856D3,
NSUnderlyingError=0x15e09de00 {
Error Domain=NSPOSIXErrorDomain
Code=13 "Permission denied"
}
}
This error means that the directory cannot be created because of a permission error. That's where I'm lost as the only reason I can see would be if I'm creating a file outside of my app's sandbox.
The code generating this error:
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString *directory = [documentsDirectory stringByAppendingPathComponent:documentsPathAndUUIDs];
NSError *error = nil;
if (![[NSFileManager defaultManager] createDirectoryAtPath:directory
withIntermediateDirectories:YES
attributes:nil
error:&error]) {
NSError(#"Unable to create directory at path %#. Error: %#", directory, error);
}
A couple things worth noting:
This path isn't saved, it's regenerated every time, so it's not as if the app container had changed between installs;
The users seem to have available disk space;
This affects at least iOS 9 (I don't have enough reports to know if it also affects iOS 10)
Would anyone have a hint of why this could happen?

Do you have sudo/chown privileges on /var? If not and you're running an OS post Mavericks, you may need to restart in safety mode and disable CSRUtil
Documentation on CSRUtil

Related

iOS - Can't Read File Located In Documents Directory

I am trying to read a file in which I successfully downloaded and saved in the Documents directory. However, when I try to read it, if fails.
Here is the error:
2016-03-28 21:00:26.585 App[569:4103] Path is /var/mobile/Applications/3AFA2430-C0DC-44CD-95F8-A89D82B2C348/Documents/combo.bin
2016-03-28 21:00:26.603 App[569:4103] Error in reading Error Domain=NSCocoaErrorDomain Code=257 "The operation couldn’t be completed. (Cocoa error 257.)" UserInfo=0x17df29d0 {NSFilePath=/var/mobile/Applications/3AFA2430-C0DC-44CD-95F8-A89D82B2C348/Documents/combo.bin, NSUnderlyingError=0x17df90b0 "The operation couldn’t be completed. Permission denied"}
Here is my code:
NSError *error;
NSData *firmwareContentData = [NSData dataWithContentsOfFile:FIRMWARE_LOCAL_PATH options:NSDataReadingMappedIfSafe error:&error];
NSLog(#"Path is %#", FIRMWARE_LOCAL_PATH);
if(error)
{
NSLog(#"Error in reading %#", error);
return;
}
local path is
#define FIRMWARE_LOCAL_PATH [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"combo.bin"]
I tried using NSTemporaryDirectory(), using NSFileManager to get the contents of the file, but none of them works. Any idea why? Thanks in advance!
You have a permissions error. You don't have the right permissions to open the file. Wherever you got it from, you're locked out. You might try to download it in the simulator, and check it through Apple's file system to see what permissions it actually downloaded with. The path is:
~/Library/Developer/CoreSimulator/Devices//data/Containers/Data/Application//Documents.
Replace the two big random strings with the directories that show a mod date of today, or NSLog the real path from your iOS app.

iOS-Creating a directory in Documents

I'm trying to create a folder in my documents directory and I want to be able to do it without typing out /Users/(username)/Documents/Foo/Bar
NSString *directoryPath = [NSString stringWithFormat:#"%#/Documents/Foo/Bar", NSHomeDirectory()];
BOOL isDir;
NSFileManager *fileManager= [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:directoryPath isDirectory:&isDir])
if(![fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:NULL])
NSLog(#"Error: Create folder failed %#", directoryPath);
This doesn't work when I try using NSHomeDirectory() with it. But if I typed out the full path /Users/(username)/Documents/Foo/Ba it works. How can it be done to not have to know the users folder?
EDIT:
directoryPath becomes
/Users/(username)/Library/Developer/CoreSimulator/Devices/FAB78255-38D2-49BE-9683-7A0676EA2288/data/Containers/Data/Application/67B0AACE-572A-4808-9535-D221AEEB9EFA/Foo/Bar
I just want /Users/(username)
This is an iOS app. The "Documents" folder of an iOS app's sandbox is not at all related to the user's "Documents" folder on their computer.
Since you appear to be running your iOS in the simulator, the path you are getting is more like what you should be seeing. You do not want a path in the user's home directory.
Keep in mind that you can't get access to the "Documents" folder of an iOS app using NSHomeDirectory(). That may have worked in older versions of iOS but it fails in iOS 8 and later. The proper code needs to be something like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsFolder = paths[0];
NSString *directoryPath = [documentsFolder stringByAppendingPathComponent:#"Foo/Bar"];

How to persist a file under NSHomeDirectory()?

I am using NSKeyedArchiver and NSKeyedUnarchiver to implement cache function for my app.
In order to load the cache file each time the app launches, I store the cache file under NSHomeDirectory(). The code (C function) is as following:
NSString* getArchivePathForId(NSString* modelId)
{
NSString *cacheIdentifier = #"CacheIdentifier";
NSString *archiveDirPath = [NSHomeDirectory() stringByAppendingFormat:#"/tmp/%#/cachedModel/%#", getAppVersion(), cacheIdentifier];
NSError* error;
if (![[NSFileManager defaultManager] fileExistsAtPath:archiveDirPath]) {
if (![[NSFileManager defaultManager] createDirectoryAtPath:archiveDirPath
withIntermediateDirectories:YES
attributes:nil
error:&error])
{
NSLog(#"Create directory tmp/cachedModel directory error: %#", error);
return nil;
}
}
NSString *archivePath = [archiveDirPath stringByAppendingFormat:#"/%#", modelId];
return archivePath;
}
It works fine as long as the App is running or coming back to live from the background mode. But once the app is terminated and re-run, the cached archive file is deleted.
Is there any way to persist the archive file so that I can load the cache stored last time when the app was launched.
I have already realised that each time the app is launched, the application id part of the NSHomeDirectory() is different. Does this have anything to do with my issue?
The issue is the "tmp" directory name at the top level. Generally files are saved under the "Documents" directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];`
Persistent caches are generally placed under the "Library" directly, use NSLibraryDirectory.
See: File System Programming Guide
tmp/
Use this directory to write temporary files that do not need to persist between launches of your app. Your app should remove files from this directory when they are no longer needed; however, the system may purge this directory when your app is not running.

Error copying file from app bundle

I used the FireFox add-on SQLite Manager, created a database, which saved to my desktop as "DB.sqlite". I copied the file into my supporting files for the project. But when I run the app, immediately I get the error
"Assertion failure in -[AppDelegate copyDatabaseIfNeeded], /Users/Mac/Desktop/Note/Note/AppDelegate.m:32 2014-08-19 23:38:02.830
Note[28309:60b] Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Failed to create writable
database file with message 'The operation couldn’t be completed.
(Cocoa error 4.)'.' First throw call stack: "...
Here is the App Delegate Code where the error takes place
-(void) copyDatabaseIfNeeded
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if (!success)
{
NSString *defaultDBPath = [[ [NSBundle mainBundle
] resourcePath] stringByAppendingPathComponent:#"DB.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
I am very new to Sqlite, so I maybe I didn't create a database correctly in the FireFox Sqlite manager, or maybe I didn't "properly" copy the .sqlite file in? (I did check the target membership in the sqlite and it correctly has my project selected. Also, the .sqlite file names all match up perfectly.)
In iOS, you can't write a file in your app's bundle. The entire bundle is read-only.
You should create the database (sqlite file) inside the NSDocumentDirectory in order to work on it.
Please visit site below for tutorial:
http://objectivecwithsuraj.blogspot.in/2012/10/database-implementation-using-sqlite-in.html
Sample Code:
https://github.com/surajwebo/SQLite-Demonstration-

App does not store any content in document directory but Appstore reject

I am new to iOS development. My app got rejected from the review, stating the following reason,
2.23 Apps must follow the iOS Data Storage Guidelines or they will be rejected
We found that your app does not follow the iOS Data Storage Guidelines, which is required per the App Store Review Guidelines.
I am not storing my DB file in documents directory. Here's my code,
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [libraryPath stringByAppendingPathComponent:#"DatabaseFolder"];
NSURL *pathURL = [NSURL fileURLWithPath:path];
BOOL isDirectory = NO;
if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) {
if (isDirectory) {
return pathURL;
} else {
// Handle error. ".data" is a file which should not be there...
[NSException raise:#"'Private Documents' exists, and is a file" format:#"Path: %#", path];
}
}
NSError *error = nil;
if (![[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error]) {
[NSException raise:#"Failed creating directory" format:#"[%#], %#", path, error];
}
return pathURL;
How to reproduce a crash or bug that only App Review or users are seeing?
The iOS Data Storage guideline document (login required to view) says,
Everything in your app’s home directory is backed up, with the exception of the application bundle itself, the caches directory, and temp directory.
This means even your NSLibraryDirectory directory contents gets backed up to iCloud. To resolve this you have following options,
Use the /tmp directory for storage
Use the /Caches directory for storage
Only use the /Documents directory for user-generated content that cannot be re-created.
Set the do not backup attribute on the file using setResourceValue:forKey:error: method of NSURL.
Here is how you can mark a resource for not backing up to iCloud.
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(#"Error excluding %# from backup %#", [URL lastPathComponent], error);
}
return success;
}
Hope that helps!
I assume the reviewer doesn't like that you are storing the database in the library folder and there within one created by you. If you read the mentioned guidelines you'll see that you shouldn't store there.
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
I had this problem for a while also. So I made a class to handle this for me. There are different rules of where you can store stuff in different OS's. So my class checked the OS and returned a proper data director for each one and even handled the migration of data from one location to the other if the OS was updated.
But pretty much today you could just support the 5.1 and up location and be fine.
The key is that you need to set your do not backup attribute also.
I just put in a github here: https://github.com/badweasel/BWFileManager

Resources