web-dev-qa-db-fra.com

Comment obtenir la progression du téléchargement dans AFNetworking 2.0?

J'utilise AFURLSessionManager pour créer une nouvelle tâche de téléchargement:

AFURLSessionManager* manager = ...

NSProgress* p = nil;
NSURLSessionDownloadTask* downloadTask =
        [manager downloadTaskWithRequest:request
                                 progress:&p
                              destination:^NSURL*(NSURL* targetPath, NSURLResponse* response) {...}
                        completionHandler:^(NSURLResponse* response, NSURL* filePath, NSError* error) {...}
        ];
[downloadTask resume];

Le fichier est téléchargé correctement, cependant, comment puis-je recevoir des notifications de progression?

p est toujours défini sur nil. J'ai déposé un problème pour cela.

J'ai également essayé d'appeler setDownloadTaskDidWriteDataBlock sur le gestionnaire, et j'y reçois des notifications de progression mais je les reçois toutes regroupées après le fichier a été téléchargé.

On dirait que cette zone est encore un peu boguée dans AFNetworking 2.0

Des idées?

25
gregschlom

Vous devez observer la propriété fractionCompleted de votre objet NSProgress à l'aide de KVO:

NSURL *url = [NSURL URLWithString:@"http://www.hfrmovies.com/TheHobbitDesolationOfSmaug48fps.mp4"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
NSProgress *progress;
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request progress:&progress destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
    // …
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
    [progress removeObserver:self forKeyPath:@"fractionCompleted" context:NULL];
    // …
}];

[downloadTask resume];
[progress addObserver:self
            forKeyPath:@"fractionCompleted"
               options:NSKeyValueObservingOptionNew
               context:NULL];

Ajoutez ensuite la méthode d'observateur:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"fractionCompleted"]) {
        NSProgress *progress = (NSProgress *)object;
        NSLog(@"Progress… %f", progress.fractionCompleted);
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

Bien sûr, vous devez vérifier les paramètres keyPath et/ou object pour décider si c'est l'objet/la propriété que vous souhaitez observer.

Vous pouvez également utiliser le setDownloadTaskDidWriteDataBlock: méthode de AFURLSessionManager (dont AFHTTPSessionManager hérite) pour définir un bloc pour recevoir les mises à jour de la progression du téléchargement.

[session setDownloadTaskDidWriteDataBlock:^(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
    NSLog(@"Progress… %lld", totalBytesWritten);
}];

Cette méthode AFNetworking mappe le URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite: méthode du protocole NSURLSessionDownloadDelegate vers un mécanisme de blocage plus pratique.

BTW, l'implémentation KVO d'Apple est gravement endommagée. Je recommande d'utiliser une meilleure implémentation comme celle proposée par Mike Ash avec MAKVONotificationCenter . Si vous êtes intéressé à lire pourquoi le KVO d'Apple est cassé, lisez Key-Value Observing Done Right par Mike Ash.

45
Sendoa

Pour télécharger le fichier avec l'état d'avancement, utilisez ce code

 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

NSURL *URL = [NSURL URLWithString:@"http://..."];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];


NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress)
{
    NSLog(@"Progress: %f", downloadProgress.fractionCompleted);
    if (progressBlock) {
                    progressBlock(downloadProgress);
                }
} destination:^NSURL *(NSURL *targetPath, NSURLResponse *response)
{
    NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
    return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error)
{
    if (response && successBlock) {
                    successBlock(response,filePath);
                }
    NSLog(@"File downloaded to: %@", filePath);
}];

[downloadTask resume];
0
DURGESH Chaurasiya

Solutions simples pour Swift:

let sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
let sessionManager = AFURLSessionManager(sessionConfiguration: sessionConfiguration)
let request = NSURLRequest(URL: url)
let sessionDownloadTask = sessionManager.downloadTaskWithRequest(request, progress: nil, destination: { (url, response) -> NSURL in

            return destinationPath.URLByAppendingPathComponent(fileName) //this is destinationPath for downloaded file

            }, completionHandler: { response, url, error in

                //do sth when it finishes
        })

Vous avez maintenant 2 options:

  1. Utilisation de UIProgressView et setProgressWithDownloadProgressOfTask:

    progressView.setProgressWithDownloadProgressOfTask(sessionDownloadTask, animated: true)
    
  2. Utilisation de AFURLSessionManager et setDownloadTaskDidWriteDataBlock:

    sessionManager.setDownloadTaskDidWriteDataBlock { session, sessionDownloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
    
        let progress = Float(totalBytesWritten)/Float(totalBytesExpectedToWrite)
            //do sth with current progress
    }
    

A la fin n'oubliez pas:

sessionDownloadTask.resume()
0