yeahdixon
yeahdixon

Reputation: 6934

AFNetworking crashes , downloading large files 200MB+

I have no issues downloading files under 250MBs, but when i am trying to download 250MB + zips the app just crashes unannounced with no error. Sometimes it goes through, sometimes it does not. Leaks confirm no bloat or memory loss.

ALSO i noticed now that the crash only happens when im debugging with xcode. When i run the app and download the larger files when im no debugging there are no issues

Do i need to approach AFNetworking classes differently when downloading a larger file?

here is my code

NSURL* url=[BFAppGlobals getServerURL:[M.Properties objectForKey:@"zip_path" ]];
NSMutableURLRequest  *request = [NSMutableURLRequest requestWithURL:url];
[request setTimeoutInterval:3600];


 AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc]  initWithRequest:request] autorelease];

NSString* writePath=[BFAppGlobals getContentResourcePathForFile:strFile];

[delegate onStartDownload:M];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:writePath append:YES];

[operation setDownloadProgressBlock:^(NSInteger bytesRead, NSInteger totalBytesRead, NSInteger totalBytesExpectedToRead) {

    int b=totalBytesRead ;
    int total=totalBytesExpectedToRead;
    float perc=(float)b/(float)total;
    M.progress=perc;
    [((NSObject*)delegate) performSelectorOnMainThread:@selector(onDataReceviedFromRequest:) withObject:M   waitUntilDone:YES];

}];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

     NSDictionary* params=[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:writePath,writeDirectory, M, nil] forKeys:[NSArray arrayWithObjects:@"Path",@"Dir",@"Model", nil]];
    [self performSelectorInBackground:@selector(unzipDownloaded:) withObject:params];


} 
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"fail! %@", [error localizedDescription]);
    [delegate onErrorDownload:M WithError:[error localizedDescription]];
    ActiveModel=nil;
}];

[operation start];



****************************  UPDATE ADDED CRASH LOG ***************************************

    Thread 0 Crashed:
    0   libobjc.A.dylib                 0x37d24fbc objc_msgSend + 16
    1   Foundation                      0x35502508 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 12
    2   CoreFoundation                  0x381aa570 ___CFXNotificationPost_block_invoke_0 + 64
    3   CoreFoundation                  0x381360c8 _CFXNotificationPost + 1400
    4   Foundation                      0x354763f4 -[NSNotificationCenter postNotificationName:object:userInfo:] + 60
    5   Foundation                      0x35477c24 -[NSNotificationCenter postNotificationName:object:] + 24
    6   BFiPad                          0x0006d2fc 0x1000 + 443132
    7   CoreFoundation                  0x3813d224 -[NSObject performSelector:withObject:] + 36
    8   Foundation                      0x35517750 __NSThreadPerformPerform + 344
    9   CoreFoundation                  0x381b2afc __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 8
    10  CoreFoundation                  0x381b22c8 __CFRunLoopDoSources0 + 208
    11  CoreFoundation                  0x381b106e __CFRunLoopRun + 646
    12  CoreFoundation                  0x381344d6 CFRunLoopRunSpecific + 294
    13  CoreFoundation                  0x3813439e CFRunLoopRunInMode + 98
    14  GraphicsServices                0x37f0bfc6 GSEventRunModal + 150
    15  UIKit                           0x31cb473c UIApplicationMain + 1084
    16  BFiPad                          0x00003f72 0x1000 + 12146
    17  BFiPad                          0x00003f30 0x1000 + 12080

Upvotes: 3

Views: 2605

Answers (3)

pajevic
pajevic

Reputation: 4657

I know that this question is old but the problem still seems to be relevant so I will post my solution anyway.

I have had the same problem where it would crash after downloading around 250MB and found out that it was caused by the fact that the download progress block was called every time a few bytes were downloaded which means that it gets called A LOT. Many times each second. So when the delegate method (which presumably does some stuff) gets called from here it can become quite memory intensive.

My solution was to track the download progress and only call the delegate method if the change is significant (I decided on more than 1%):

[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
    float progress = ((float)totalBytesRead) / totalBytesExpectedToRead;
    if ((progress - totalProgress) > 0.01) {
        totalProgress = progress;
        [delegate updateProgress:progress];
    }
}];

float totalProgress is an instance variable.

This fix reduced the memory usage from around 280MB at the point of the crash to around 30MB which my app was using already. I.e. there was no noticeable memory rise during the download process (assuming your are downloading directly to a file, not to the memory).

Upvotes: 1

yeahdixon
yeahdixon

Reputation: 6934

It seems that this is only happenning in debug mode. Running out of debug mode or on release more solves this problem

Upvotes: 2

mattt
mattt

Reputation: 19544

It doesn't look like operation is owned by anything in particular, so there's no guarantee that it will stick around in memory. Try using an NSOperationQueue (perhaps one attached to an AFHTTPClient, which would clean up a lot of that code), or setting this as a retained property in the controller initiating the upload.

Upvotes: 1

Related Questions