Get A File

Summary

An easy way to fetch a file from the cloud, for example the Personal Web Sharing built into OS X on Macintosh.

Introduction

Fetching a file and saving it to disk.

For Testing

Using the Cocoa API of OS X: Simple, but it blocks. You'd never do this in a real application, because your app would appear frozen while it was waiting for the server to finish sending the file.

NSURL *url = [NSURL URLWithString:@"http://www.turbozen.com/howto"];
NSData *fileInRAM = [NSData dataWithContentsOfURL:url];
NSString *outputPath = YourFunctionThatReturnsPath();
[fileInRAM writeToFile:outputPath atomically:YES];

For Real

A real app would use code like this, to start fetching the file, then when the file is complete, your callback gets called to put the data where you want.

You probably have some catch-all, long-lived class where the commands of your application are implemented. Add two member variables to its .h file:

NSURLConnection *http_;
NSMutableData *httpData_;

and in the corresponding .m file, add the code to support this to your -(void)dealloc method:

-(void)dealloc {
...
  [http_ cancel];
  [http_ release];
  http_ = nil;
  [httpData_ release];
  http_ = nil;
...
  [super dealloc];
}

You'll not use @property and @synthesize, but explicitly write the setter:

- (void)setHTTP:(NSURLConnection *)http {
  if (http_ != http) {
    [http_ cancel];
    [http_ release];
    http_ = [http retain];
  }
}

Now the code to start a file moving to your box is:

- (IBAction)fetchFile:(id)sender {
...
NSURL *url = [NSURL URLWithString:@"http://www.turbozen.com/howto"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:@"My Program/1.0.0" forHTTPHeaderField:@"User-Agent"];
NSURLConnection *connection = 
    [NSURLConnection connectionWithRequest:request delegate:self];
[self setHTTP:connection];
} // we just return back to the main event loop

That sets the file moving to you. You'll need code to actually catch the file your "self" object above must implement some delegate methods that will be called back by the connection:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
  if (httpData_) {
    httpData_ appendData:data];
  } else {
    httpData_ = [data mutableCopy];
  }
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// at this point httpData holds the entire file. You can save it to disk.
  [httpData_ release];
  http_ = nil;
}

- (void)connection:(NSURLConnection *)connection 
  didFailWithError:(NSError *)error {
  [httpData_ release];
  http_ = nil;
}

See Also

Further Work

A real program might provide manage multiple simultaneous connections, with an array of connections currently open, and a queue of pending connections.

Conclusion

This page has presented OS X Cocoa code for fetching a file from the web and saving it to disk.