tags:

views:

209

answers:

3

Hi All,

I want to download a file to the downloads folder. I searched google for this and found the NSURLDownload class. I've read the page in the dev center and created this code (with some copy and pasting) this code:

@implementation Downloader
@synthesize downloadResponse;

- (void)startDownloadingURL:(NSString*)downloadUrl destenation:(NSString*)destenation {
    // create the request
    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:downloadUrl]
                                              cachePolicy:NSURLRequestUseProtocolCachePolicy
                                          timeoutInterval:60.0];
    // create the connection with the request
    // and start loading the data
    NSURLDownload  *theDownload=[[NSURLDownload alloc] initWithRequest:theRequest
                                                              delegate:self];
    if (!theDownload) {
        NSLog(@"Download could not be made...");
    }
}

- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename {
    NSString *destinationFilename;
    NSString *homeDirectory=NSHomeDirectory();

    destinationFilename=[[homeDirectory stringByAppendingPathComponent:@"Desktop"]
                         stringByAppendingPathComponent:filename];
    [download setDestination:destinationFilename allowOverwrite:NO];
}

- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error {
    // release the connection
    [download release];

    // inform the user
    NSLog(@"Download failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}

- (void)downloadDidFinish:(NSURLDownload *)download {
    // release the connection
    [download release];

    // do something with the data
    NSLog(@"downloadDidFinish");
}

- (void)setDownloadResponse:(NSURLResponse *)aDownloadResponse {
    [aDownloadResponse retain];
    [downloadResponse release];
    downloadResponse = aDownloadResponse;
}

- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response {
    // reset the progress, this might be called multiple times
    bytesReceived = 0;

    // retain the response to use later
    [self setDownloadResponse:response];
}

- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(unsigned)length {
    long long expectedLength = [[self downloadResponse] expectedContentLength];

    bytesReceived = bytesReceived+length;

    if (expectedLength != NSURLResponseUnknownLength) {
        percentComplete = (bytesReceived/(float)expectedLength)*100.0;
        NSLog(@"Percent - %f",percentComplete);
    } else {
        NSLog(@"Bytes received - %d",bytesReceived);
    }
}

-(NSURLRequest *)download:(NSURLDownload *)download
          willSendRequest:(NSURLRequest *)request
         redirectResponse:(NSURLResponse *)redirectResponse {
    NSURLRequest *newRequest=request;
    if (redirectResponse) {
        newRequest=nil;
    }
    return newRequest;
}
@end

But my problem is now, it doesn't appear on the desktop as specified. And I want to put it in downloads and not on the desktop... What do I have to do?

EDIT: Last stack:

#0  0x92169ed7 in objc_msgSend
#1  0x01390090 in ??
#2  0x90443107 in URLDownload::didReceiveResponse
#3  0x903ecfc0 in URLConnectionClient::_clientSendDidReceiveResponse
#4  0x90465705 in URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload
#5  0x904658b2 in URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload
#6  0x903e0ace in URLConnectionClient::processEvents
#7  0x903e096f in MultiplexerSource::perform
#8  0x953df15b in __CFRunLoopDoSources0
#9  0x953dcc1f in __CFRunLoopRun
#10 0x953dc0f4 in CFRunLoopRunSpecific
#11 0x953dbf21 in CFRunLoopRunInMode
#12 0x96bc10fc in RunCurrentEventLoopInMode
#13 0x96bc0eb1 in ReceiveNextEventCommon
#14 0x96bc0d36 in BlockUntilNextEventMatchingListInMode
#15 0x9775d135 in _DPSNextEvent
#16 0x9775c976 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]
#17 0x9771ebef in -[NSApplication run]
#18 0x97716c85 in NSApplicationMain
#19 0x00002628 in main at main.m:13
+1  A: 

You never used that destination string in -startDownloadingURL:destination:. Presumably you meant to call -[NSURLDownload setDestination:allowOverwrite:].

-[NSFileManager URLsForDirectory:NSDownloadsDirectory inDomains:NSUserDomainMask] should give you a start at getting the downloads directory. I haven't needed to use this method myself, and I think the docs say that it isn't guaranteed that there actually is a directory at the return of the method. So, you need a fallback for that case.

Ken
I found an error in another part of the code... Now I get the error: 'Downloader' may not respond to '-alloc'. What does this mean??
dododedodonl
It sounds like you send the alloc message to an instance of your downloader rather than the class. Maybe I wasn't clear, but I took your code and added the call to -[NSURLDownload setDestination:allowOverwrite:], and it succeeded in downloading a file! I didn't look over code for other errors (like leaks), but that should get you going.
Ken
I wrote a lower case D in stead of upper case... Another (small) question: How can I debug a `Program received signal: “EXC_BAD_ACCESS”` error
dododedodonl
dododedodoni: Open the Debugger window, look at the stack trace, find your methods or functions in the stack, and look at what you were doing when it broke.
Peter Hosey
How can I see that? I only see some strange code (like `0x92169ed7 <+0023> mov 0x20(%edx),%edi` with a red arrow before that line).
dododedodonl
You're looking at Apple's code, not your code (or you're running a Release build—only debug Debug builds). The editor view will tell you what class you're looking at. As I said, look in the stack trace to find your own methods or functions. Select one, then look at where it was in your code when it broke.
Peter Hosey
I use debug build... I get to see first my own code (this is no problem, it goes as expected trough the code) and after that I see much code like that above and get an `EXC_BAD_ACCESS` error...
dododedodonl
In the stack trace, the only class from my own code what is running is main... But I didn't change anything... I added my last stack above...
dododedodonl
+1  A: 

http://allseeing-i.com/ASIHTTPRequest/How-to-use

Oz
A: 
#0  0x92169ed7 in objc_msgSend
#1  0x01390090 in ??
#2  0x90443107 in URLDownload::didReceiveResponse

Sounds like you didn't hold on to your Downloader, so it died, and the download then sent a delegate message to your dead Downloader object.

Make sure something keeps on owning the Downloader as long as it needs something downloaded. You can use Instruments's ObjectAlloc instrument to track the creation, retentions, and releases of the Downloader, to see which of the releases you shouldn't be doing.

Don't forget to read or re-read the memory management docs (recently rewritten), while you're at it.

Peter Hosey