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.
Getting Download progress with AFNetworking 2.0 + NSProgress + Custom ProgressView
Use AFURLConnectionOperation -setDownloadProgressBlock:, updating the progress with the ratio of totalBytesRead over totalBytesExpectedToRead each time the block is called.
To update your UI element, just call the update through the main thread:
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
});
How to get download progress with AFHTTPSessionManager in AFNetworking 3.0
Link in comments was missleading (NSURLSessionDownloadTask
). Sorry about that.
Code below should work though.
Assumption: this code is placed in AFHTTPSessionManager
subclass with an NSURLSessionDataTask *testTask
ivar declared. It should be easy enough modify as needed.
Vital part of code taken from this answer
- (void)test
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://eoimages.gsfc.nasa.gov/images/imagerecords/78000/78797/nwpassage_tmo_2012199_lrg.jpg"]];
testTask = [self dataTaskWithRequest:request
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error)
{
//...
NSLog(@"error");
}
else
{
//...
UIImage *result = responseObject;
NSLog(@"Success: %@",NSStringFromCGSize(result.size));
}
}];
[self setDataTaskDidReceiveDataBlock:^(NSURLSession *session,
NSURLSessionDataTask *dataTask,
NSData *data)
{
if (dataTask.countOfBytesExpectedToReceive == NSURLSessionTransferSizeUnknown)
return;
if (dataTask != testTask)
return;
NSUInteger code = [(NSHTTPURLResponse *)dataTask.response statusCode];
if (!(code> 199 && code < 400))
return;
long long bytesReceived = [dataTask countOfBytesReceived];
long long bytesTotal = [dataTask countOfBytesExpectedToReceive];
NSLog(@"... %lld/%lld",
bytesReceived,
bytesTotal);
}];
[testTask resume];
}
AFNetworking 2.0 track file upload progress
The interface of AFHTTPSession
doesn't provide a method to set a progress block. Instead, you'll have to do the following:
// 1. Create `AFHTTPRequestSerializer` which will create your request.
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
// 2. Create an `NSMutableURLRequest`.
NSMutableURLRequest *request =
[serializer multipartFormRequestWithMethod:@"POST" URLString:@"http://www.myurl.com"
parameters:dataToPost
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData
name:@"attachment"
fileName:@"myimage.jpg"
mimeType:@"image/jpeg"];
}];
// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperation *operation =
[manager HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Success %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Failure %@", error.description);
}];
// 4. Set the progress block of the operation.
[operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten,
long long totalBytesWritten,
long long totalBytesExpectedToWrite) {
NSLog(@"Wrote %lld/%lld", totalBytesWritten, totalBytesExpectedToWrite);
}];
// 5. Begin!
[operation start];
In addition, you don't have to read the image via UIImage
and then compress it again using JPEG to get an NSData
. Just use +[NSData dataWithContentsOfFile:]
to read the file directly from your bundle.
How to show ProgressBar With AFNetworking AFHTTPRequestOperationManager
You set the download-progress-block inside the success block, which is a bit too late ;)
Try this:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperation *operation = [manager GET:@"https:urlWithJson" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Complete");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
myProgressView.progress = (float)totalBytesRead / totalBytesExpectedToRead;
}];
AFNetworking Progress method
I would recommend using the following template for loading images with progress:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFImageResponseSerializer serializer];
manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
[manager GET:url.absoluteString parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
float progress = downloadProgress.fractionCompleted;
} success:^(NSURLSessionTask *task, id responseObject) {
UIImage *responseImage = responseObject;
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(Failed with error: %@", error);
}];
and this template for downloading videos with progress:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
float progress = downloadProgress.fractionCompleted;
} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
if(error) {
NSLog(Error %@", error);
}
else {
NSString *path = filePath.relativeString;
}
}
}];
[downloadTask resume];
I hope this helps!
How to use Progress parameter in AFNetworking 2.0
Any time an argument is given as **
it means that you're supposed to pass in the pointer to the pointer to an existing object, not a pointer to the actual object as you would normally do.
In this case, you pass in a pointer to a pointer to an NSProgress
object and then observe the changes in that object in order to get the updates.
Example:
// Create a progress object and pass it in
NSProgress *progress;
[sessionManager uploadTaskWithRequest:request fromFile:fileURL progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
// Completion code
}];
// Observe fractionCompleted using KVO
[progress addObserver:self
forKeyPath:@"fractionCompleted"
options:NSKeyValueObservingOptionNew
context:NULL];
Then it gets reported in:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
if ([keyPath isEqualToString:@"fractionCompleted"] && [object isKindOfClass:[NSProgress class]]) {
NSProgress *progress = (NSProgress *)object;
NSLog(@"Progress is %f", progress.fractionCompleted);
}
}
How to set download status of UIProgressView in UILabel using AFNetworking?
For more detail see https://stackoverflow.com/a/19380812/5235106
Here is the answer
- (IBAction)ActionPerform:(UIButton *)sender
{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *strURL = [NSURL URLWithString:URL];
NSURLRequest *request = [NSURLRequest requestWithURL:strURL];
NSProgress *progress;
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:&progress 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)
{
NSLog(@"File downloaded to: %@", filePath);
}];
[self.ProgressView setProgressWithDownloadProgressOfTask:downloadTask animated:YES];
[downloadTask resume];
[progress addObserver:self
forKeyPath:@"fractionCompleted"
options:NSKeyValueObservingOptionNew
context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"fractionCompleted"]) {
NSProgress *progress = (NSProgress *)object;
// update the label text use progress
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
@end
Related Topics
Unbalanced Calls to Begin/End Appearance Transitions for <Uitabbarcontroller: 0X197870>
Make App Appear as iOS 8 Suggested App at Lockscreen
How to Use Uiscrollview in Interface Builder
How to Add "Done" Button to Numpad in iOS Using Swift
How Big Should a Uibarbuttonitem Image Be
Implement Document Picker in Swift (Ios)
Using Uiimagepickercontroller in Landscape Orientation
Swift 3 Core Data Delete Object
Converting Between Nsdata and Base64 Strings
App Rejected Because of Advertisingidentifier in Facebook Sdk and Flurry Sdk
Updating iOS Badge Without Push Notifications
How to Do Some Stuff in Viewdidappear Only Once
The Executable Gets Signed with Invalid Entitlements in Xcode
@Binding and Foreach in Swiftui
Ios 8.1 Simulator Always Uses Us Keyboard Layout Despite German Hardware Keyboard