How to track progress of multiple simultaneous downloads with AFNetworking?

Viewed 5162

I am using AFNetworking to download files that my app uses for a sync solution. At certain times, the app downloads a series of files as a batch unit. Following this example, I run the batch like this:

NSURL *baseURL = <NSURL with the base of my server>;
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL];

// as per: https://stackoverflow.com/a/19883392/353137
dispatch_group_t group = dispatch_group_create();

for (NSDictionary *changeSet in changeSets) {
    dispatch_group_enter(group);

    AFHTTPRequestOperation *operation =
    [manager
     POST:@"download"
     parameters: <my download parameters>
     success:^(AFHTTPRequestOperation *operation, id responseObject) {
         // handle download success...
         // ...
         dispatch_group_leave(group);

     }
     failure:^(AFHTTPRequestOperation *operation, NSError *error) {
         // handle failure...
         // ...
         dispatch_group_leave(group);
     }];
    [operation start];
}
// Here we wait for all the requests to finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // run code when all files are downloaded
});

This works well for the batch downloads. However, I want to display to the user an MBProgressHUD which shows them how the downloads are coming along.

AFNetworking provides a callback method

[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
}];

... which lets you update a progress meter pretty easily, simply by setting the progress to totalBytesRead / totalBytesExpectedToRead. But when you have multiple downloads going simultaneously that is hard to keep track of on a total basis.

I have considered having an NSMutableDictionary with a key for each HTTP operation, with this general format:

NSMutableArray *downloadProgress = [NSMutableArray arrayWithArray:@{
   @"DownloadID1" : @{ @"totalBytesRead" : @0, @"totalBytesExpected" : @100000},
   @"DownloadID2" : @{ @"totalBytesRead" : @0, @"totalBytesExpected" : @200000}
}];

As each operation's download progresses, I can update the totalBytesRead for that specific operation in the central NSMutableDictionary -- and then total up all the totalBytesRead and totalBytesExpected' to come up with the total for the whole batched operation. However, AFNetworking's progress callback methoddownloadProgressBlock, defined as^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead){}does not include the specific operation as a callback block variable (as opposed to thesuccessandfailure` callbacks, which do contain the specific operation as a variable, making it accessible). Which makes it impossible, as far as I can tell, to determine which operation specifically is making the callback.

Any suggestions on how to track the progress of multipole simultaneous downloads using AFNetworking?

5 Answers
Related