I’m getting strange behavior writing NSString and NSData objects to relative file paths. Here’s an example:
NSString *string = @"I am a file!";
NSError *error = nil;
NSString *fileName = @"text.txt";
BOOL written = [string writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (written) {
NSLog(@"Successfully written to file.");
} else {
NSLog(@"Error: %@", [error localizedDescription]);
}
When I run this I always get “Successfully written to file.”, but the file is never there. Somehow the program thinks it was successful and no error is generated.
What am I doing wrong? (I’m on Mac OS X Lion)
This writes to the current directory. The default current directory when you run something under Xcode 4 is going to be
~/Library/Developer/Xcode/DerivedData/<prodDir>/Build/Products/<configuration>. You can override this using a Scheme. When you run a program from the commandline, then the current directory is whatever the current directory was when you ran the program. If you use Finder to launch the app, then the current directory will often be/.In principle, it’s fine to write the current working directory. It’s very common to do this in command-line apps. So regarding @craig’s comment about
writeToFile:expecting an absolute path, I don’t think that’s really true. It expects and writes to a path. It doesn’t care if it’s absolute or relative. This is a Foundation class, and is just as useful in a command-line program as a GUI.But in a GUI app, you should avoid relative paths. In principle, you could set the current directory and then write the file, but this is usually a bad idea in a large program since it’s not thread safe (there is only one cwd for the whole program). And GUI apps tend to have somewhat unpredictable current directories, so it doesn’t make for a good user experience.
But to the question of why you didn’t get an error, it’s because it probably successfully wrote it. You just didn’t know where to look.