views:

2458

answers:

4

In an iPhone app I currently have code for downloading a file from the Web to the iPhone and saving it to disk.

The problem is that if the file is large then the memory usage of the app skyrockets and the app crashes.

I am sure I am just not doing it the "proper" way.

Currently I have the following:

mediaData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:path]];
[mediaData writeToFile:fullPath atomically:YES];
[mediaData release];

As I mentioned this works for something like a picture, but not for something like say a video clip, as the app crashes.

What is the proper way to do this to keep my app from crashing? My thought was maybe sockets, but as I have not done much socket programming, I am not sure.

Thanks

+5  A: 

You can use NSURLConnection which runs asynchronously and delivers data in manageable chunks.

Chris Lundie
You would also want to use an API like NSFileHandle to write the data to disk as it comes in.Of course for a video clip, would you not be better off using the movie player's built-in downloading support?
Mike Abdullah
No because it will not allow you to save the video for future use
kdbdallas
NSURLConnection with NSFileHandle was the answer. NSURLConnection alone still crashed.
kdbdallas
+2  A: 

As NSURLDownload is not available on the iPhone, you might want to use NSURLConnection and buffer some data in a NSMutableData using connection:didReceiveData: delegate method. This article describes some of this: http://dannyg.com/iapps/Blog/Entries/2009/2/16_The_Joy_in_Discovering_You_Are_an_Idiot.html

François P.
A: 

kdbdallas Can you share the solution?

Thanks!

MAbbas
NSURLConnection with NSFileHandle was the answer. NSURLConnection alone still crashed
kdbdallas
A: 

i am trying to download an audio file using NSURLConnection. The file is aboout 1.2 MB. I see the asynchronous call being made 2-3 time but when I see the size of the file that is downloaded it is only 36 kb. Any idea what is going on?

Here is my code snippet

In one of initializer method NSURLRequest *theRequest = [NSURLRequest requestWithURL:theURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:120];

    /* create the NSMutableData instance that will hold the received data */
    receivedData = [[NSMutableData alloc] initWithLength:0];

    //receivedData=[[NSMutableData data] retain];


    /* Create the connection with the request and start loading the
     data. The connection object is owned both by the creator and the
     loading system. */

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:theRequest 
                                                                  delegate:self 
                                                          startImmediately:YES];

Rest of the methods are pasted below - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse )response { / This method is called when the server has determined that it has enough information to create the NSURLResponse. It can be called multiple times, for example in the case of a redirect, so each time we reset the data. */

NSString *caf = @"1.caf" ;
if ([filePath hasSuffix:(NSString *)caf])
{

    //[self.receivedData appendData:data];
    l = [response expectedContentLength];
    NSLog(@"%d %d %s",i, l, filePath);
}   
[self.receivedData setLength:0];

/* Try to retrieve last modified date from HTTP header. If found, format  
 date so it matches format of cached image file modification date. */

if ([response isKindOfClass:[NSHTTPURLResponse self]]) {
    NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields];
    NSString *modified = [headers objectForKey:@"Last-Modified"];
    if (modified) {
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss zzz"];
        self.lastModified = [dateFormatter dateFromString:modified];
        [dateFormatter release];
    }
    else {
        /* default if last modified date doesn't exist (not an error) */
        self.lastModified = [NSDate dateWithTimeIntervalSinceReferenceDate:0];
    }
}

}

-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse { NSURLRequest *newRequest=request; if (redirectResponse) { newRequest=nil; } return newRequest; }

  • (void) connection:(NSURLConnection *)connection didReceiveData:(NSData )data { / Append the new data to the received data. */ //NSLog(filePath); NSString *caf = @"1.caf" ; if ([filePath hasSuffix:(NSString *)caf]) { i++; [self.receivedData appendData:data]; l = [receivedData length]; NSLog(@"%d %d %s",i, l, filePath); }

    [self.receivedData appendData:data]; }

  • (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { //URLCacheAlertWithError(error); [self.delegate connectionDidFail:self]; [connection release]; }

  • (NSCachedURLResponse *) connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse )cachedResponse { / this application does not use a NSURLCache disk or memory cache */ return nil; }

  • (void) connectionDidFinishLoading:(NSURLConnection *)connection { NSString *caf = @"1.caf" ;

    if ([filePath hasSuffix:(NSString *)caf]) { NSLog(@"%d %d %s",i, l, filePath); }

    NSLog(filePath);
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath] == NO) 
    {
        /* file doesn't exist, so create it */
        [[NSFileManager defaultManager] createFileAtPath:filePath 
                                            contents:receivedData 
                                              attributes:nil];
    
    
    
    //statusField.text = NSLocalizedString (@"Newly cached image", 
    //                                    @"Image not found in cache or new image available.");
    
    } else { //statusField.text = NSLocalizedString (@"Cached image is up to date", // @"Image updated and no new image available."); } /* reset the file's modification date to indicate that the URL has been checked */ NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:[NSDate date], NSFileModificationDate, nil]; if (![[NSFileManager defaultManager] setAttributes:dict ofItemAtPath:filePath error:&error]) { //URLCacheAlertWithError(error); //if (error != NULL){ // NSLog(error); //} } [dict release]; [connection release];

    }

amitabh
This should be moved to a separate question.
raidfive