O2U
O2U

Reputation: 439

AFNetworking and Downloading Binary Files

Has anyone had any success downloading larger files using AFNetworking? Here is the code that I'm using right now:

NSFileManager *fm = [NSFileManager defaultManager];

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dfwPath =  [documentsDirectory stringByAppendingPathComponent:@"sync_download.db"];

//Delete the existing one if our last sync was interrupted...
[fm removeItemAtPath:[documentsDirectory stringByAppendingPathComponent:@"sync_download.db"] error:nil];

NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setObject:@"sync"   forKey:@"app"];
[parameters setObject:@"dl"     forKey:@"cmd"];
[parameters setObject:version   forKey:@"ver"];

[AFHTTPRequestOperation addAcceptableContentTypes:[NSSet setWithObject:@"application/bin"]];

AFMyClient *client = [AFMyClient sharedClient];

NSMutableURLRequest* rq = [client requestWithMethod:@"POST" path:@"myserver/ol.php" parameters:parameters];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:rq];

operation.outputStream = [NSOutputStream outputStreamToFileAtPath:dfwPath append:NO];

[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
    NSLog(@"The bytes download: %llu of %llu", totalBytesRead, totalBytesExpectedToRead);

    //float percentDone = ((float)((int)totalBytesRead) / (float)((int)totalBytesExpectedToRead));

}];

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

    NSLog(@"Finished downloading: %@", [operation responseString]);

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

    NSLog(@"Error downloading: %@",[error debugDescription]);
}];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];

What happens is that the file gets created but its always zero bytes even though the amount being downloaded is about 10MB. The "setDownloadProgressBlock" is never reached but the "setCompletionBlockWithSuccess" is.

Here is how I'm setting the headers on the server before sending the download data:

        $data = file_get_contents($filename);
        header('Pragma: public'); 
        header('Content-Type: application/bin');
        header('Content-Disposition: attachment; filename="'.basename($filename).'";');
        header('Content-Transfer-Encoding: binary');
        header('Content-Length: '.strlen($data));       
        echo $data;

Using the older ASIHttpRequest libraries this worked perfectly. So if anyone has an idea what's going on I'd be very grateful.

Upvotes: 2

Views: 3364

Answers (2)

O2U
O2U

Reputation: 439

Okay I figured it out. Turns out I was not sending my data from the server the most efficient way and also I cleaned up my HTTP Headers like so:

        $size = filesize($filename);
        header('Pragma: no-cache'); 
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="'.basename($filename).'";');
        header('Content-Transfer-Encoding: binary');
        header('Accept-Ranges: bytes');
        header('Cache-Control: max-age=604800');
        header("Content-Length: $size");        
        readfile($filename);

Upvotes: 1

mattt
mattt

Reputation: 19544

Three things:

First, you may need to schedule your output stream in a runloop, to ensure that downloading works as intended.

Second, it could be that the NSOperationQueue that you're creating in that method is being deallocated before the operation is finished. Instead, you should enqueue your HTTP request operation in the AFHTTPClient operation queue.

Third, unrelated: you should use AFHTTPClient -HTTPRequestOperationWithRequest:success:failure: instead of manually creating an AFHTTPRequestOperation class, and doing setCompletionBlockWithSuccess:failure:. Without using the client constructor, you miss out on the registered operations logic and default headers.

Upvotes: 1

Related Questions