How to get download progress in AFNetworking 2.0?
Solution 1
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.
Solution 2
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];
Related videos on Youtube
gregschlom
Updated on November 22, 2020Comments
-
gregschlom over 3 years
I am using AFURLSessionManager to create a new download task:
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];
The file gets downloaded fine, however, how do I get progress notifications?
p
is always set to nil. I've filed an issue for that.I've also tried to call
setDownloadTaskDidWriteDataBlock
on the manager, and I do get progress notifications there but I receive them all grouped together after the file has been downloaded.Seems like this area is still a bit buggy in AFNetworking 2.0
Any ideas?
-
Miles over 10 yearsAgreed. I'm not able to get the downloader to even work. It cancels immediately.
-
TPoschel over 10 yearsIf you want to be iOS6/7 compliant, you should use
AFHTTPRequestOperation
.AFURLSessionManager
only works on iOS 7. I've posted an answer showing how to get download progress usingAFHTTPRequestOperation
.
-
-
Shmidt over 10 yearsTerminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFBackgroundDownloadTask fractionCompleted]: unrecognized selector sent to instance 0xd888b40'
-
Sendoa over 10 yearsThe
fractionCompleted
property belongs to theNSProgress
object. -
alejandromp over 10 yearsBe aware that in KVO you should not call super if you handle the notification.
-
Sendoa over 10 yearsThanks @alejandromp . I've just edited it. BTW, I recommend a better implementation of KVO like the one proposed by Mike Ash: github.com/mikeash/MAKVONotificationCenter.
-
Cameron Lowell Palmer over 10 yearsIn general, you might use the pattern NSStringFromSelector(@selector(fractionCompleted)) instead of using compiler opaque strings like @"fractionCompleted".
-
Everus about 10 yearsmissed typed NSUR should be NSURL also there is an error for "control reaches end of non-void block"
-
Praveen-K almost 10 yearsHow to add extra headers to AFHTTPSessionManager. Error Domain=NSURLErrorDomain Code=-1102 "You do not have permission to access the requested resource." UserInfo=0xb96ba30 NSLocalizedDescription=You do not have permission to access the requested resource. This is how i am doing [self.sessionManager.requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [self.sessionManager.requestSerializer setValue:[NSString stringWithFormat:@"Bearer %@",authToken] forHTTPHeaderField:@"Authorization"]; but when i check the request header it shows as (null)
-
Manav almost 10 yearsNote: You'll need to use
setTaskDidSendBodyDataBlock
for data tasks (instead of thesetDownloadTaskDidWriteDataBlock
mentioned in the answer). -
Aaron Vegh over 9 yearsMight be helpful to note that the manager variable in this code snippet is an instance of AFURLSessionManager.
-
Amin Negm-Awad over 7 years@CameronLowellPalmer What is the advantage of generating the string at runtime? Except of the cases, where it is not possible to do so.
-
Genevios almost 5 yearsAwesome example! Thanks!