ios - afhttprequestoperation - ¿Cómo obtener progreso de descarga en AFNetworking 2.0?
alamofire example (4)
Debes observar la propiedad fractionCompleted
de tu objeto NSProgress usando 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];
Luego agrega el método del observador:
- (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];
}
}
Por supuesto, debe verificar los keyPath
y / o del object
para decidir si ese es el objeto / propiedad que desea observar.
También puede usar el método setDownloadTaskDidWriteDataBlock:
de AFURLSessionManager
(del cual AFHTTPSessionManager
hereda) para establecer un bloqueo para recibir actualizaciones de progreso de descarga.
[session setDownloadTaskDidWriteDataBlock:^(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
NSLog(@"Progress… %lld", totalBytesWritten);
}];
Este método AFNetworking asigna la URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
método del protocolo NSURLSessionDownloadDelegate
a un mecanismo de bloque más conveniente.
Por cierto, la implementación de KVO de Apple está gravemente dañada. Recomiendo usar una mejor implementación como la propuesta por Mike Ash con MAKVONotificationCenter . Si está interesado en leer por qué se rompe el KVO de Apple, lea Observación del valor clave bien hecho por Mike Ash.
Estoy usando AFURLSessionManager para crear una nueva tarea de descarga:
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];
El archivo se descarga bien, sin embargo, ¿cómo obtengo notificaciones de progreso?
p
siempre se establece en nulo. He presentado un issue para eso.
También he intentado llamar a setDownloadTaskDidWriteDataBlock
en el administrador, y recibo notificaciones de progreso allí, pero las recibo todas agrupadas después de que se haya descargado el archivo.
Parece que esta área todavía tiene un poco de buggy en AFNetworking 2.0
¿Algunas ideas?
Me enfrenté a un problema similar, y encontré una solución.
Consulte el siguiente enlace: http://cocoadocs.org/docsets/AFNetworking/2.0.1/Categories/UIProgressView+AFNetworking.html
#import <AFNetworking/UIKit+AFNetworking.h>
y use el método adicional disponible para su UIProgressView
setProgressWithDownloadProgressOfTask: animated:
Como lo hice
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response){
NSURL *documentsDirectoryPath = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) firstObject]];
return [documentsDirectoryPath URLByAppendingPathComponent:[targetPath lastPathComponent]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error){
NSLog(@"File downloaded to: %@", filePath);
}];
[self.progressView setProgressWithDownloadProgressOfTask:downloadTask animated:YES];
[downloadTask resume];
Para descargar el archivo con estado de progreso usa este código
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];
Soluciones simples para 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
})
Ahora tienes 2 opciones:
Usando
UIProgressView
ysetProgressWithDownloadProgressOfTask:
progressView.setProgressWithDownloadProgressOfTask(sessionDownloadTask, animated: true)
Usando
AFURLSessionManager
ysetDownloadTaskDidWriteDataBlock:
sessionManager.setDownloadTaskDidWriteDataBlock { session, sessionDownloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in let progress = Float(totalBytesWritten)/Float(totalBytesExpectedToWrite) //do sth with current progress }
Al final no te olvides de:
sessionDownloadTask.resume()