Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [52]
int main (int argc, const char * argv[]) {
@autoreleasepool {
NSError *error = nil;
NSString *str = [[NSString alloc] initWithContentsOfFile:@"/etc/resolv.conf"
encoding:NSASCIIStringEncoding
error:&error];
if (!str) {
NSLog(@"read failed: %@", [error localizedDescription]);
} else {
NSLog(@"resolv.conf looks like this: %@", str);
}
}
return 0;
}
Writing an NSData object to a file
An NSData object represents a buffer of bytes. For example, if you fetch some data from a URL, you get an instance of NSData. And you can ask an NSData to write itself to a file. Create a new Foundation Command Line Tool named ImageFetch that fetches an image from the Google website into an instance of NSData. Then ask the NSData to write its buffer of bytes to a file:
#import int main (int argc, const char * argv[]) { @autoreleasepool { NSURL *url = [NSURL URLWithString: @"http://www.google.com/images/logos/ps_logo2.png"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSError *error = nil; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:&error]; if (!data) { NSLog(@"fetch failed: %@", [error localizedDescription]); return 1; } NSLog(@"The file is %lu bytes", [data length]); BOOL written = [data writeToFile:@"/tmp/google.png" options:0 error:&error]; if (!written) { NSLog(@"write failed: %@", [error localizedDescription]); return 1; } NSLog(@"Success!"); } return 0; } Build and run the program. Open the resulting image file in Preview. Note that the writeToFile:options:error: method takes a number that indicates options to be used in the saving process. The most common option is NSDataWritingAtomic. Let’s say that you’ve already fetched an image, and you’re just re-fetching and replacing it with a newer version. While the new image is being written, the power goes off. A half-written file is worthless. In cases where a half-written file is worse than no file at all, you can make the writing atomic. Add this option: NSLog(@"The file is %lu bytes", [data length]); BOOL written = [data writeToFile:@"/tmp/google.png" options:NSDataWritingAtomic error:&error]; if (!written) { NSLog(@"write failed: %@", [error localizedDescription]); return 1; } Now, the data will be written out to a temporary file, and, when the writing is done, the file is renamed the correct name. This way, you either get the whole file or nothing. Reading an NSData from a file #import int main (int argc, const char * argv[]) { @autoreleasepool { NSURL *url = [NSURL URLWithString: @"http://www.google.com/images/logos/ps_logo2.png"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSError *error; // This method will block until all the data has been fetched NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:&error]; if (!data) { NSLog(@"fetch failed: %@", [error localizedDescription]); return 1; } NSLog(@"The file is %lu bytes", [data length]); BOOL written = [data writeToFile:@"/tmp/google.png" options:NSDataWritingAtomic error:&error]; if (!written) { NSLog(@"write failed: %@", [error localizedDescription]); return 1; } NSLog(@"Success!"); NSData *readData = [NSData dataWithContentsOfFile:@"/tmp/google.png"]; NSLog(@"The file read from the disk has %lu bytes", [readData length]); } return 0; } Build and run the program. 24 Callbacks You have been living a sweet and simple existence. In the real world, applications run for hours and your objects act as slaves to the stream of events pouring in from the user, the clock, the network,
You can also create an instance of NSData from the contents of a file. Add two lines to your program:
Thus far, your code has been the boss. It has been sending messages to standard Foundation objects, like instances of NSString and NSArray, and telling them what to do. Thus far, your programs have run and exited in milliseconds.