Search code examples
iosobjective-cdownloadafnetworking

calculating total progress of downloading multiple file with AFNetworking


I want to download multiple file and then display a total progress to the user.

but the problem is here I dont know how should I calculate total progress .

here is what I do: first I get to totalBytes Expected to receive from all of the files:

for (NSURL candidateUrl in UrlsList)
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:candidateURL];
                        //setting HTTPMethod of request from GET to HEAD to download header files of requests, so we can get file size before downloaing file
                        [request setHTTPMethod:@"HEAD"];

                        getTotalImagesBytesOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
                        [getTotalImagesBytesOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
                         {
                             //setting totalImagesBytesExpectedToRead of all images. we use it to know how many bytes we should download for all the images
                              totalImagesBytesExpectedToRead += [operation.response expectedContentLength];


                         } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                             NSLog(@"Error: %@", error);
                         }];

                        [operationQueue addOperation:getTotalImagesBytesOperation];
}

after estimating total files size:

        //downloading images
    for (NSURL *imageUrl in imagesURLList) {
        NSURLRequest *request = [NSURLRequest requestWithURL:imageUrl];
        AFImageRequestOperation *downloadImageOperation = [AFImageRequestOperation imageRequestOperationWithRequest:request
                                                                                  imageProcessingBlock:nil

                                                                                               success: ^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {                                                                                      
NSLog(@"success")
}
failure: ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
                                                                                                       NSLog(@"%@", [error localizedDescription]);
                                                                                                   }];

        [operationQueue addOperation:downloadImageOperation];

        [downloadImageOperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead)
        {

          **HOW TO CALCULATE TOTAL PROGRESS**
}

I don't know how to calculate total size!! the values we have: totalBytesOfAllTheFiles, totalBytesRead and totalBytesExpectedToRead for the current file which above method gives you, indexOfCurrentFile and countOfFiles.

be cautious setDownloadProgressBlock called hundreds a time.

does anyone have any idea? (sorry for bad formatting of code!)


Solution

  • Here is how I achieved that: first create an NSOperationQueue:

    // Add the operation to a queue
    // It will start once added
    //calculating images byte size
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    [operationQueue setMaxConcurrentOperationCount:1];
    foreach (NSURL *candidateURL in urlList )
    {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:candidateURL];
                        //setting HTTPMethod of request from GET to HEAD to download header files of requests, so we can get file size before downloaing file
                        [request setHTTPMethod:@"HEAD"];
    
                        AFHTTPRequestOperation *getTotalImagesBytesOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
                        [getTotalImagesBytesOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
                         {
                             //setting totalImagesBytesExpectedToRead of all images. we use it to know how many bytes we should download for all the images
                             totalImagesBytesExpectedToRead += [operation.response expectedContentLength];
    
    
                         } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                             NSLog(@"Error: %@", error);
                         }];
    
                        [operationQueue addOperation:getTotalImagesBytesOperation];
    }
    
     //downloading images which should be downloaded
    for (NSURL *imageUrl in imagesShouldBeDownlaoded) {
        NSURLRequest *request = [NSURLRequest requestWithURL:imageUrl];
    
        AFHTTPRequestOperation *downloadFileOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
        //we must provide file path with file name and its extension
        NSString *fileName = [self getImageName:[imageUrl absoluteString]];
        downloadFileOperation.outputStream = [NSOutputStream outputStreamToFileAtPath:[[ImageManager applicationDocumentsDirectory] stringByAppendingPathComponent:fileName] append:NO];
    
        [downloadFileOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation , id response)
         {
             NSLog(@"file saved");
    
         }failure:^(AFHTTPRequestOperation *operation, NSError *error)
         {
             completionBlock(NO, error);
             NSLog(@"%@", [error localizedDescription]);
         }];
    
        [operationQueue addOperation:downloadFileOperation];
    
        [downloadFileOperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead)
         {
             totalBytesDownloaded += bytesRead;
    
             //total progress from 0.0 to 1.0
             progress = ((float)totalBytesDownloaded/(float)totalImagesBytesExpectedToRead);
             if(progress == 1)
             {
                 completionBlock(YES, nil);
             }
             progressCallback(progress);
        }];
    

    operationQueue works as a FIFO list, first calculate images byte size, then starts to download all images