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];
Related
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 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.
I need to check the size of file from a URL. I get the file size perfectly when downloading file with AFNetworking.
AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
// Success Callback
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Failure Callback
}];
and get file size in another block
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
}];
But i need to check file size before initiating download request, so that i can prompt to user. I have also tried another method
NSURL *url = [NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSLog(#"original = %d", [data length]);
But it blocks the UI, coz it download all data to calculate its size.
Is there any way to check file size before downloading? Any help is appreciated.
If the server supports it you can make a request to just get the headers (HEAD, as opposed to GET) without the actual data payload and this should include the Content-Length.
If you can't do that then you need to start the download and use expectedContentLength of the NSURLResponse.
Basically, create an instance of NSMutableURLRequest and call setHTTPMethod: with the method parameter set to #"HEAD" (to replace the default which is GET). Then send that to the server as you currently request for the full set of data (same URL).
here is the code:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:candidateURL];
[request setHTTPMethod:#"HEAD"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Content-lent: %lld", [operation.response expectedContentLength]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
I'm retrieving JSON data using AFNetworking lib, and wanted to add a completion block as follows:
-(void)getData{
NSString *link=#"http://localhost:8080/address/address/address/";
NSURL *url= [ NSURL URLWithString:link];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
arrayofA=[JSON valueForKeyPath:#"a"];
arrayofB=[JSON valueForKeyPath:#"b"];
[[self techTableView] reloadData];
} failure:nil];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
//-- This block gets invoked periodically as the download progress
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(totalBytesRead * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void){
dispatch_async(dispatch_get_main_queue(), ^{
// HUD treatment
});
});
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Completed:");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
}
When I added the completion bloc I no longer have a result, nothing is shown in the screen, and noticed that AFJSONRequestOperation bloc is not executed, I printed a log there and it's not shown.
What could be the problem?
Thank you very much.
Throw this code away:
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Completed:");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Instead, put your logging into the blocks on the JSONRequestOperationWithRequest:success:failure: (where you currently have a success block but no failure block, and the success block is being removed by the code that you should remove).
In setDownloadProgressBlock, just push to the main thread and update your UI. Don't bother trying to create a delay, that will only lead to apparently random behaviour. Also, don't try to use the result of the download, that should only be done in the success block.