How to get download progress in AFNetworking 2.0?
You should observe the fractionCompleted
property of your NSProgress
object using 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];
Then add the observer method:
- (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]; }}
Of course, you should check keyPath
and/or object
parameters to decide if that's the object/property you want to observe.
You can also use the setDownloadTaskDidWriteDataBlock:
method from AFURLSessionManager
(from which AFHTTPSessionManager
inherits) to set a block for receiving download progress updates.
[session setDownloadTaskDidWriteDataBlock:^(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) { NSLog(@"Progress… %lld", totalBytesWritten);}];
This AFNetworking method maps the URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
method from NSURLSessionDownloadDelegate
protocol to a more convenient block mechanism.
BTW, Apple's KVO implementation is severely broken. I recommend using a better implementation like the one proposed by Mike Ash with MAKVONotificationCenter. If you are interested in reading why Apple's KVO is broken, read Key-Value Observing Done Right by Mike Ash.
I faced a similar problem, and found a solution.
Check the link below:http://cocoadocs.org/docsets/AFNetworking/2.0.1/Categories/UIProgressView+AFNetworking.html
#import <AFNetworking/UIKit+AFNetworking.h>
and use the additional method available to your UIProgressView
setProgressWithDownloadProgressOfTask:animated:
How I did it:
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];
Simple solutions for 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 })
Now you have 2 options:
Using
UIProgressView
andsetProgressWithDownloadProgressOfTask:
progressView.setProgressWithDownloadProgressOfTask(sessionDownloadTask, animated: true)
Using
AFURLSessionManager
andsetDownloadTaskDidWriteDataBlock:
sessionManager.setDownloadTaskDidWriteDataBlock { session, sessionDownloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in let progress = Float(totalBytesWritten)/Float(totalBytesExpectedToWrite) //do sth with current progress}
At the end do not forget about:
sessionDownloadTask.resume()