Can't write to document directory - ios

I'm trying to copy a json file from the application bundle to the Document directory, but surprisingly i'm not able to do that. Here's the code:
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [array lastObject];
NSString *path = [docDir stringByAppendingPathExtension:#"themes.json"];
if (![[NSFileManager defaultManager] fileExistsAtPath:path])
{
NSString *themesPath = [[NSBundle mainBundle] pathForResource:#"themes" ofType:#"json"];
NSError *error = nil;
[[NSFileManager defaultManager] copyItemAtPath:themesPath toPath:path error:&error];
if (error)
NSLog(#"Error %#", error);
}
It produces the following error:
Error Domain=NSCocoaErrorDomain Code=513 "The operation couldn’t be completed. (Cocoa error 513.)" UserInfo=0x194a0e90 {NSSourceFilePathErrorKey=/var/mobile/Applications/ACED3EF9-B0D8-49E8-91DE-37128357E509/Frinder.app/themes.json, NSUserStringVariant=(
Copy
), NSFilePath=/var/mobile/Applications/ACED3EF9-B0D8-49E8-91DE-37128357E509/Frinder.app/themes.json, NSDestinationFilePath=/var/mobile/Applications/ACED3EF9-B0D8-49E8-91DE-37128357E509/Documents.themes.json, NSUnderlyingError=0x194a0400 "The operation couldn’t be completed. Operation not permitted"}
After a search i've found this question and tried to modify my code as follows:
if (![[NSFileManager defaultManager] fileExistsAtPath:path])
{
NSString *themesPath = [[NSBundle mainBundle] pathForResource:#"themes" ofType:#"json"];
NSData *data = [NSData dataWithContentsOfFile:themesPath];
BOOL success = [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil];
if (!success)
NSLog(#"Fail");
}
but it doesn't work either. success variable is NO. The last thing i tried was:
[data writeToFile:path atomically:YES];
but still in vain. it returns NO.
I need to note that the issue arises on a device only. On a simulator it works all right.
Can anybody give me a clue?

The first example is correct on one thing:
[docDir stringByAppendingPathExtension:#"themes.json"];
should be:
[docDir stringByAppendingPathComponent:#"themes.json"];
This becomes clear we you read the error message, you see that it tries to write the file to /var/mobile/Applications/ACED3EF9-B0D8-49E8-91DE-37128357E509/Documents.themes.json. Notice that there a . where there should be a /.
The stringByAppendingPathExtension: is used for adding a extension to a file, jpg, txt, html,.....
stringByAppendingPathComponent will add a file to a path, by adding the correct directory separator, you case /.
You second example will definitely fail since the app bundle is readonly.

Related

Empty documents directory after creating file with NSFileHandle

I'm writing an application for the Apple watch. I'm using the following method (from this SE answer) to write to a log file:
- (void) writeLogWith: (NSString *) content {
//Get the file path
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fileName = [documentsDirectory stringByAppendingPathComponent:#"whathappened.md"];
//create file if it doesn't exist
if(![[NSFileManager defaultManager] fileExistsAtPath:fileName])
[[NSFileManager defaultManager] createFileAtPath:fileName contents:nil attributes:nil];
//append text to file (you'll probably want to add a newline every write)
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:fileName];
[file seekToEndOfFile];
[file writeData:[content dataUsingEncoding:NSUTF8StringEncoding]];
[file closeFile];
return;
}
I'm running it by plugging in my phone and running it directly on my watch. The function is definitely executing (I've stepped thought with the debugger) and it also knows that the file exists and doesn't repeatedly try and create it.
Xcode tells me that the file information is:
Printing description of documentsDirectory:
/var/mobile/Containers/Data/PluginKitPlugin/8503AD6C-6EC9-4522-A867-27109B01B615/Documents
Printing description of documentsDirectory:
(NSString *) documentsDirectory = 0x16d66890
Printing description of fileName:
(NSString *) fileName = 0x16d66950
Printing description of fileName:
/var/mobile/Containers/Data/PluginKitPlugin/8503AD6C-6EC9-4522-A867-27109B01B615/Documents/whathappened.md
I'd like to know if it's writing things correctly, but when I look at the container (following these SE answers), the documents directory is empty.
My question is: where did my file go? And how can I find it?
I think what might be giving you problems is the NSFileHandle object. I have written thousands upon thousands of files to the documents folder and I have never used NSFileHandle to do this. Simply use the built in method on NSString to write your string to the file path.
Try this:
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [[documentsDirectory stringByAppendingPathComponent:#"whathappened"] stringByAppendingPathExtension:#"md"];
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
}
NSString *string = #"The String You Want To Write.";
NSError *error;
[string writeToFile:filePath atomically:false encoding:NSUTF8StringEncoding error:&error];
if (error) {
NSLog(#"There was an error writing file\n%#", error.localizedDescription);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSLog(#"File exists :)");
}
else {
NSLog(#"File does not exist :(");
}
From other research, the answer appears to be:
If you are storing a file on the Apple Watch, it is stored in it's own container, which isn't visible via xcode.
It indeed, appears to be related to this bug report: https://openradar.appspot.com/radar?id=5021353337946112, found via this SE: How to export shared container of an iOS App with Xcode6.2?

NSFileManager moving a file shows error

I am trying to create two log files and replace content in the second file with the content in the first file.
My code for creating log in AppDelegate
NSArray *paths3 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory3 = [paths3 objectAtIndex:0];
logPath3 = [documentsDirectory3 stringByAppendingPathComponent:#"console4.log"];
if(![[NSFileManager defaultManager] fileExistsAtPath:logPath3])
[[NSFileManager defaultManager] createFileAtPath:logPath3 contents:[NSData data] attributes:nil];
NSLog(#"path %#",logPath3);
freopen([logPath3 cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
NSArray *paths2 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory2 = [paths2 objectAtIndex:0];
logPath2 = [documentsDirectory2 stringByAppendingPathComponent:#"console3.log"];
if(![[NSFileManager defaultManager] fileExistsAtPath:logPath2])
[[NSFileManager defaultManager] createFileAtPath:logPath2 contents:[NSData data] attributes:nil];
NSLog(#"path %#",logPath2);
freopen([logPath2 cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
_isFileOneCreated =YES;
code to move content
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
NSError * err;
if ([filemgr moveItemAtPath:
logPath2 toPath:
logPath3 error: &err])
NSLog (#"Day 3 Move successful");
else
NSLog (#"Day 3 Move failed %#",[err localizedDescription]);
But i get an error 516.
(Cocoa error 516.)" UserInfo=0x16dba220 {NSSourceFilePathErrorKey=/var/mobile/Containers/Data/Application/274E9843-2C8E-45F3-BD41-EA392F50C7AC/Documents/console3.log, NSUserStringVariant=(
Move
), NSFilePath=/var/mobile/Containers/Data/Application/274E9843-2C8E-45F3-BD41-EA392F50C7AC/Documents/console3.log, NSDestinationFilePath=/var/mobile/Containers/Data/Application/274E9843-2C8E-45F3-BD41-EA392F50C7AC/Documents/console4.log, NSUnderlyingError=0x16da63f0 "The operation couldn’t be completed. File exists"}
Help me solve my issue
moveItemAtPath does not allow you to overwrite the file with same name. See this Question Thread.
All you need to do is delete the file at target location before you overwrite with new one. Use the below code. This will do the trick but i advice you to take precaution to have the backup of your file just in case move doesn't work for some unknown reason.
NSFileManager *filemgr = [NSFileManager defaultManager];
NSError * err;
[filemgr removeItemAtPath:logPath3 error:&err];
if ([filemgr moveItemAtPath:logPath3 toPath:logPath2 error: &err])
NSLog (#"Day 3 Move successful");
else
NSLog (#"Day 3 Move failed %#",[err localizedDescription]);

Delete Cache in iOS. Cocoa error 513

My app have to download many image from web. So I want to provide a button to clear caches of this images.
Are these images save in /Library/Caches ?
I Assuming that there are stored in the /Library/Caches. So I attempt to delete these files by:
filemgr = [NSFileManager defaultManager];
NSError *error;
[filemgr removeItemAtPath: [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] error:&error]
// OR
[filemgr removeItemAtPath:[NSHomeDirectory() stringByAppendingString:#"/Library/Caches"] error:&error];
Both are error with The operation couldn’t be completed. (Cocoa error 513.) in iOS device, but worked in Simulator.
Thank you for answer!
You cant remove "/Library/Caches". You need to remove all items in"/Library/Caches"
NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
for (NSString *filePath in [[NSFileManager defaultManager] enumeratorAtPath:path])
{
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:filePath] error:&error];
if (error)
{
NSLog(#"%#",error.description);
}
}
You can not remove direct Cache folder. You have to parse every file from Cache folder and remove them.
Thanks.

iOS - iPhone application documents "No such directory"?

I'm trying to use the method seen in the solution here to delete all the files in the iPhone documents directory for the application I'm writing. I've made some minor changes to the code in the solution in order to pass in the string location of the documents directory. My version of the code is the following:
NSString *directory = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] absoluteString];
NSLog(#"%#", directory);
NSError *error = nil;
NSArray *directoryContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directory error:&error];
if (error == nil) {
for (NSString *path in directoryContents) {
NSString *fullPath = [directory stringByAppendingPathComponent:path];
BOOL removeSuccess = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
if (!removeSuccess) {
// Error handling
}
}
} else {
// Error handling
NSLog(#"%#", error);
}
When I attempt to run this however, the setting of directoryContents fails due to what's being passed being interpreted as a non-existent directory. Specifically, the two NSLog() statements I have put in the code returns the following:
2013-04-22 11:48:22.628 iphone-ipcamera[389:907] file://localhost/var/mobile/Applications/AB039CDA-412B-435A-90C2-8FBAADFE6B1E/Documents/
2013-04-22 11:48:22.650 iphone-ipcamera[389:907] Error Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be completed. (Cocoa error 260.)" UserInfo=0x1d5232c0 {NSUnderlyingError=0x1d54c420 "The operation couldn’t be completed. No such file or directory", NSFilePath=file://localhost/var/mobile/Applications/AB039CDA-412B-435A-90C2-8FBAADFE6B1E/Documents/, NSUserStringVariant=(
Folder
)}
As far as I can see the path being printed to the NSLog looks correct so I'm not sure what I'm doing wrong. Can anyone point out to me where my mistake is? Thank you much!
Your code to get the value of directory isn't quite right. You want:
NSURL *directoryURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSString *directory = [directoryURL path];
Calling absoluteString on NSURL gives you a file URL. You don't want a file URL, you want the file URL converted to a file path. This is what the path method does.
Another way is:
NSString *directory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

Cocoa Error 256 when getting file list in application resources folder

The following code is outputting The operation couldn’t be completed. (Cocoa error 256.) and the filenames NSArray is null/empty. There should be files in this folder, any ideas whats broken?
NSError *error;
NSFileManager *fm = [NSFileManager defaultManager];
filenames = [fm contentsOfDirectoryAtPath:[[NSBundle mainBundle] pathForResource:#"files" ofType:nil] error:&error];
NSLog(#"%#", [error localizedDescription]);
EDIT
[[NSBundle mainBundle] pathForResource:#"files" ofType:nil] is returning null for some reason
Nil extensions aren't folders, iOS treats them like files. You have to use -resourcePath then append the name of your folder instead.

Resources