OK, first of all, a few things. You've sent the controller a
Bam message, passing downloadProgress as the argument. Firstly, methods (like Bam) should start with a lowercase letter and a method executed in a thread should take one argument, which Bam doesn't take—you don't need to pass downloadProgress as the object to the NSThread; pass nil instead. The only reason downloadProgress works is that it's an ivar; on a side note, it's best to statically type outlets in IB. So, your ivar declaration should begin with:
IBOutlet NSProgressIndicator *downloadProgress;
There's absoutely no reason why
[urlContents writeToFile:[@"~/Documents/applewebsite.html" stringByExpandingTildeInPath] atomically:YES];
[downloadProgress displayIfNeeded];
needs to be in an NS_HANDLER block. NS_DURING, NS_HANDLER and NS_ENDHANDLER are designed to catch exceptions. However, neither writeToFile:atomically: nor displayIfNeeded raise any exceptions. So you can remove that. Also, why are calling displayIfNeeded? It forces the progress indicator to redraw if it's been marked as needing display. You don't need to do this.
Actually, after reading through your code, there's no need to either (a) set your progress indicator to use threaded animation, or (b) do what you're doing in a separate thread.
Because you want to find out the status of the download, you'll have to use NSURLHandle.
Here's what each file should contain:
Controller.h
Code:
#import <Cocoa/Cocoa.h>
@interface Controller : NSObject <NSURLHandleClient>
{
IBOutlet NSProgressIndicator *downloadProgress;
}
- (IBAction)download:(id)sender;
@end
Controller.m
Code:
- (IBAction)download:(id)sender
{
NSURLHandle *handle;
NSURL *url;
url = [NSURL URLWithString:@"http://www.apple.com"];
handle = [NSURLHandle cachedHandleForURL:url];
[handle addClient:self];
[handle beginLoadInBackground];
}
- (void)URLHandleResourceDidBeginLoading:(NSURLHandle *)sender
{
[downloadProgress startAnimation:nil];
}
- (void)URLHandle:(NSURLHandle *)sender resourceDataDidBecomeAvailable:(NSData *)newBytes
{
if (!totalBytesToRetrieve)
{
id contentLength;
double totalBytesToRetrieve;
contentLength = [sender propertyForKeyIfAvailable:@"Content-Length"];
totalBytesToRetrieve = [contentLength doubleValue];
[downloadProgress setIndeterminate:NO];
[downloadProgress setDoubleValue:0.0];
[downloadProgress setMaxValue:totalBytesToRetrieve];
}
else
{
double existingBytesRetrieved;
double bytesRetrievedSoFar;
existingBytesRetrieved = [downloadProgress doubleValue];
bytesRetrievedSoFar = existingBytesRetrieved + [newBytes length];
[downloadProgress setDoubleValue:bytesRetrievedSoFar];
}
}
- (void)URLHandleResourceDidFinishLoading:(NSURLHandle *)sender
{
NSData *fileData;
NSString *saveFile;
fileData = [sender resourceData];
saveFile = [@"~/Documents/Apple Website.html" stringByExpandingTildeInPath];
[fileData writeToFile:saveFile atomically:YES];
}
- (void)URLHandleResourceDidCancelLoading:(NSURLHandle *)sender
{
[downloadProgress setIndeterminate:YES];
[downloadProgress stopAnimation:nil];
}
- (void)URLHandle:(NSURLHandle *)sender resourceDidFailLoadingWithReason:(NSString *)reason
{
[downloadProgress setIndeterminate:YES];
[downloadProgress stopAnimation:nil];
NSLog(@"Oops! Here's what went wrong: %@", reason);
}
It's untested, but it should work.