подсчет общего прогресса загрузки нескольких файлов с AFNetworking

Я хочу загрузить несколько файлов, а затем показать пользователю общий прогресс.

но проблема в том, что я не знаю, как рассчитать общий прогресс.

вот что я делаю: сначала я добираюсь до totalBytes, ожидаемых от всех файлов:

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];
}

после оценки общего размера файлов:

        //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**
}

Я не знаю, как рассчитать общий размер !! значения, которые у нас есть: totalBytesOfAllTheFiles, totalBytesRead и totalBytesExpectedToRead для текущего файла, который дает вам вышеуказанный метод, indexOfCurrentFile и countOfFiles.

будьте осторожны, setDownloadProgressBlock вызывается сотнями раз.

у кого-нибудь есть идеи? (извините за плохое форматирование кода!)

Не могли бы вы просто разделить totalBytesRead на totalBytesExpectedToRead?   —  person Hashem Aboonajmi    schedule 07.09.2014

@ evan.stoddard totalBytesRead/totalBytesExpectedToRead дает мне процент завершения текущего файла. не все файлы!   —  person Hashem Aboonajmi    schedule 07.09.2014

Первое соображение: вам действительно нужно быть настолько точным, чтобы использовать общее количество байтов для расчета прогресса? Я использовал общее количество загруженных файлов / общее количество файлов, которые нужно загрузить, чтобы рассчитать прогресс приложения. Это намного проще.   —  person Hashem Aboonajmi    schedule 07.09.2014

См. также:  Тип аргумента "Объект?" не может быть назначен типу параметра «Карта‹ динамический, динамический ›». GetX

Подумайте о том, когда ваши первые пять файлов имеют общий размер 1 МБ, а последние пять файлов — 100 МБ. этот расчет не годится.   —  person Hashem Aboonajmi    schedule 07.09.2014

В этом случае единственным способом может быть считывание информации об общем размере из файла данных где-нибудь в сети до начала загрузки. Если это невозможно, вам придется переосмыслить дизайн своего приложения. Вы не можете узнать размер всех файлов до их загрузки.   —  person Hashem Aboonajmi    schedule 08.09.2014

Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 2
  1. Hashem Aboonajmi

    Вот как я этого добился: сначала создайте 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 работает как список FIFO, сначала рассчитывается размер байта изображения, затем начинается загрузка всех изображений

    пожалуйста, объясните, как использовать завершенияBlock и progressCallback. Также, где вы начинаете операцию, например [downloadFileOperation Start]. Пожалуйста, прокомментируйте. Я немного застрял здесь. person Hashem Aboonajmi; 29.01.2015

    нет необходимости запускать операцию явно, операция загрузки будет запущена неявно путем добавления операции в Очередь операций. Также завершениеBlock и progressCallback — мои настраиваемые блоки, которые будут уведомлять меня о ходе загрузки, сбое или успехе загрузки. person Hashem Aboonajmi; 29.01.2015

  2. Hashem Aboonajmi

    AFNetworking3 использует dispatch_group и NSProgress для достижения этого:

    #import <Foundation/Foundation.h>
    #import <AFNetworking.h>
    
    @interface Server : NSObject
    
    @property (nonatomic, strong) AFHTTPSessionManager *manager;
    @property (nonatomic, strong) NSProgress *progress;
    
    - (void)downloadFilesWithUrls:(NSMutableArray <NSURL *>*)urls;
    
    @end
    
    
    
    #import "Server.h"
    @implementation Server
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            _manager = [AFHTTPSessionManager manager];
            _manager.requestSerializer = [AFJSONRequestSerializer serializer];
            _manager.responseSerializer = [AFJSONResponseSerializer serializer];
    
            _progress = [NSProgress progressWithTotalUnitCount:0];
            [_progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:nil];
        }
        return self;
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        NSLog(@"fractionCompleted:%lf",self.progress.fractionCompleted);
    }
    
    - (void)downloadFilesWithUrls:(NSMutableArray <NSURL *>*)urls {
        //progress
        dispatch_group_t group = dispatch_group_create();
        _progress.totalUnitCount = urls.count;
        [urls enumerateObjectsUsingBlock:^(NSURL * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
             dispatch_group_enter(group);
            NSURLRequest *request = [NSURLRequest requestWithURL:obj];
            NSURLSessionDownloadTask *task = [self.manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
            } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
                return [[[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil] URLByAppendingPathComponent:[response suggestedFilename]];
            } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
                NSLog(@"one task completion");
                dispatch_group_leave(group);
            }];
    
            NSProgress *child = [self.manager downloadProgressForTask:task];
            [self.progress addChild:child withPendingUnitCount:1];
            [task resume];
        }];
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"%lf", self.progress.fractionCompleted);
        });
    
    }
    
    @end
    
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: