I am trying to use the category UIProgressView+AFNetworking from AFNetworking UIKit.
I have an operation that uploads photos to a server. Mulitple photos at once. But my progress view isn't updating at all.
In my UIProgressView I use
[progressView setProgressWithUploadProgressOfOperation:operation animated:YES];
And my request is:
AFHTTPRequestOperation *operation =
[manager POST:url parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:#"imageFile" fileName:fileName mimeType:[NSString stringWithFormat:#"image/%#",fileMime]];
NSLog(#"Uploading...");
[SVProgressHUD showWithStatus:#"Uploading File..."];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
//Success
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//Fail
[manager.operationQueue cancelAllOperations];
}];
Try this:
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead){
double progress = (double)totalBytesRead / totalBytesExpectedToRead;
NSLog(#"Progress: %.2f", progress);
// ...
}];
I have my own progress bar, so I change its value in the setDownloadProgressBlock block.
Related
I am trying to show the Progress Bar as I download a JSON from a url. The JSON is downloading correctly but I am not sure how to show the Progress Bar. I have tried using UIProgressView but it does not display on the screen. Any suggestions would be appreciated.
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
CGRect rect = CGRectMake(width/2, height/2, width/5, height/5);
UIProgressView *myProgressView = [[UIProgressView alloc]initWithFrame:rect];
myProgressView.progressViewStyle = UIProgressViewStyleBar;
[self.view addSubview:myProgressView];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"https:urlWithJson" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead)
{
myProgressView.progress = (float)totalBytesRead / totalBytesExpectedToRead;
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"operation Completed");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"ERROR");
}];
[operation start];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"timeout Error: %#", error);
}];
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;
}];
Simple solution for Swift:
let progress: UIProgressView? //for example, reference to IBOutlet
let manager = AFHTTPRequestOperationManager()
let operation = manager.POST(query, parameters: parameters, constructingBodyWithBlock: { multipartData in
//do sth with your multipartData
}, success: { operation, response in
//success
}) { operation, error in
//failure
}
progress?.setProgressWithUploadProgressOfOperation(operation!, animated: true)
You do nothing more. This is enough to show progress on your view.
I am posting a JPEG image with some textual data to my server using AFNetworking:
- (NSArray *)postPhoto:(NSData *)jpegData withRoomType:(NSString *)roomType andDescription:(NSString *)description {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0);
__block NSArray *returnedMetaData;
AFHTTPRequestOperation *operation = [self.requestManager POST:[Constants postPhotoURLString] parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSLog(#"Room: %#", roomType);
[formData appendPartWithFormData:[roomType dataUsingEncoding:NSUTF8StringEncoding]
name:#"room"];
NSLog(#"Description: %#", description);
[formData appendPartWithFormData:[description dataUsingEncoding:NSUTF8StringEncoding]
name:#"description"];
[formData appendPartWithFileData:jpegData
name:#"image"
fileName:#"photo.jpg"
mimeType:#"image/jpeg"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
returnedMetaData = (NSArray *)responseObject;
dispatch_semaphore_signal(semaphore);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%#", error.description);
dispatch_semaphore_signal(semaphore);
}];
operation.completionQueue = queue;
[operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten,
long long totalBytesWritten,
long long totalBytesExpectedToWrite) {
NSLog(#"Wrote %lld/%lld", totalBytesWritten, totalBytesExpectedToWrite);
}];
[operation start];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return returnedMetaData;
}
Every request results in a timeout after 60 seconds:
Error Domain=NSURLErrorDomain Code=-1001 "Time-out van het verzoek." UserInfo=0x15d28d30
Judging from Wireshark, the POST request never even leaves the simulator, and Xcode indicates bandwidth usage is 0. Some other POST requests in my app work fine. Doing the exact same thing in curl as in the code above also works just fine.
Also I checked the URL and no trailing slashes are missing, whatsoever. Copy-pasting the URL to curl and doing a multipart/form-data request does produce the desired outcome.
Am I missing something here?
Thanks!
NSData *imageData = UIImageJPEGRepresentation(YOURIMAGE, 0.5);
NSDictionary * dicParamsToSend = #{#"room" : room,
#"description" : description };
AFHTTPRequestOperation *op = [manager POST:#"rest.of.url" parameters:dicParamsToSend constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
//do not put image inside parameters dictionary as I did, but append it!
[formData appendPartWithFileData:imageData name:#"image" fileName:#"photo.jpg" mimeType:#"image/jpeg"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %# <=> %#", operation.responseString, responseObject);
}failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %# <=> %#", operation.responseString, error);
}];
[op start];
This might helps you :)
I m uploading multiple image my images on server, URL is same for all.
Following is the code.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.securityPolicy.allowInvalidCertificates = YES;
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
NSDictionary *parameters = #{KEY: VALUE};
NSString *imageUrl=[NSString stringWithFormat:#"%#/user/upload/item",BASE_SERVER_ADDRESS];
AFHTTPRequestOperation *op = [manager POST:imageUrl parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSString *imageName = [NSString stringWithFormat:#"IMG00%i.png",count];
[formData appendPartWithFileData:_imageData name:#"files" fileName:imageName mimeType:#"image/png"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success: %# ***** %#", operation.responseString, responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %# ***** %#", operation.responseString, error);
}];
[op setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
double percentDone = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
//Upload Progress bar here
NSLog(#"progress updated(percentDone) : %f", percentDone);
}];
[op start];
I upload 10 images parallel and get the progress of each image individual. Now I want to cancel the specific uploading image, like 5th image.
How can I get the Operation of that image.
operationQueue has only NSOperation inside it. How will I know that specific NSOperation is the one I want to cancel.
Thanks.
You need to store operation you need to cancel in a variable, and later call [op cancel].
I am relatively new to AFNetworking 2.0. Using the code snippet below, I've been able to successfully upload a photo to my url. I would like to track the incremental upload progress, but I cannot find an example of doing this with version 2.0. My application is iOS 7, so I've opted for AFHTTPSessionManager.
Can anyone offer an example of how to modify this snippet to track upload progress?
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:#"myimage.jpg"], 1.0);
[manager POST:#"http://myurl.com" parameters:dataToPost constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:#"attachment" fileName:#"myimage.jpg" mimeType:#"image/jpeg"];
} success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(#"Success %#", responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(#"Failure %#, %#", error, [task.response description]);
}];
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.
It's true the interface of AFHTTPSessionManager doesn't provide a method to track the upload progress. But the AFURLSessionManager does.
As a inherited class of AFURLSessionManager AFHTTPSessionManager can track upload progress like this:
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:#"POST" URLString:kUploadImageURL parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImageJPEGRepresentation(image, 0.5) name:#"uploadFile" fileName:#"image" mimeType:#"image/jpeg"];
} error:nil];
NSProgress *progress;
NSURLSessionDataTask *uploadTask = [[AFHTTPSessionManager sharedManager] uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (!error) {
//handle upload success
} else {
//handle upload failure
}
}];
[uploadTask resume];
[progress addObserver:self forKeyPath:#"fractionCompleted" options:NSKeyValueObservingOptionNew context:NULL];
outside
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"fractionCompleted"] && [object isKindOfClass:[NSProgress class]]) {
NSProgress *progress = (NSProgress *)object;
//progress.fractionCompleted tells you the percent in CGFloat
}
}
Here is method 2(updated)
use KVO to track progress means self need to be alive during observation. The more elegant way is AFURLSessionManager's method setTaskDidSendBodyDataBlock, like this:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager setTaskDidSendBodyDataBlock:^(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
//during the progress
}];
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:#"POST" URLString:kUploadImageURL parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImageJPEGRepresentation(image, 0.5) name:#"uploadFile" fileName:#"image" mimeType:#"image/jpeg"];
} error:nil];
NSURLSessionDataTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (!error) {
//handle upload success
} else {
//handle upload failure
}
}];
[uploadTask resume];
I'm using AFNetworking to send a multipart form to a web-server, and i'm having some trouble with my AFHTTPRequestOperation. It's success and failure blocks are never called, after i start it.
Here is my code (a resume of it)
NSMutableURLRequest *request = [[ServerAPI sharedClient] multipartFormRequestWithMethod:#"POST" path:postUrl parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
[formData appendPartWithFileData:picture.picture_data name:#"InputFile" fileName:picture.name mimeType:#"image/jpg"];
}];
AFHTTPRequestOperation *operation = [[ServerAPI sharedClient] HTTPRequestOperationWithRequest: request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
[operation setUploadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"%f", (totalBytesRead / (float) totalBytesExpectedToRead));
}];
[[ServerAPI sharedClient] enqueueHTTPRequestOperation:operation];
I can see the logs of the progress, but success and failure blocks are never called.
picture.picture_data is a NSData initialized with a UIImageJPEGRepresentation(image, 0.7)
ServerAPI is a subclass of AFHTTPClient, and sharedCliend is a singleton method.
Which are the reasons for AFNetworking don't call my blocks, not even with an proper error message?
Thank you all!
Edit
I do a get request with the same URL just before this one, and it works as usual. The URL i'm using is: part/_layouts/UploadEx.aspx?List=%7BD432BF97-7175-40C1-8E0D-27D8661CBC90%7D&RootFolder=%2Fpwa%2Fpart%2FLibrary&Source=http%3A%2F%2Fwww%2Emysite%2Ecom%2Fpwa%2Fpart%2FLibrary%2FForms%2FAllItems%2Easpx&IsDlg=1
In your code, check your postUrl . The BaseURL+postURL must be valid. Try upload image using normal web browser using URL BaseURL+postURL.
Edit
method HTTPRequestOperationWithRequest:success:failure: does not work for file uploading, but works for json/html fetching.
Try use
AFHTTPRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:request];
[operation setUploadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"%f", (totalBytesRead / (float) totalBytesExpectedToRead));
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
[[ServerAPI sharedClient] enqueueHTTPRequestOperation:operation];