Completion block prevents AFJSONRequestOperation execution - ios

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.

Related

How to get download progress with AFHTTPSessionManager in AFNetworking 3.0

When I use AFNetworking 2, I could get progress with AFHTTPRequestOperation like this:
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:aURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:_timeoutInterval];
AFHTTPRequestOperation *imageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
imageRequestOperation.responseSerializer = [AFImageResponseSerializer serializer];
__weak AFHTTPRequestOperation *imageRequestOperationForBlock = imageRequestOperation;
[imageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// ...
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// ...
}];
[imageRequestOperation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
if (progress) {
progress((float)totalBytesRead / totalBytesExpectedToRead);
}
}];
I use AFHTTPSessionManager GET:parameters:success:failure: to get data, but I don't know how to get download progress 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];
}

Ios-Afnetworking multiple download using selector method

Handle single download via afnetworking is good my question is that how handle multiple click on different button then it call this method then process break previous.
it is bcoz suppose several button hit at time then it confuse to download. how handle multiple download in selector method,if in array of batch download then it's easy but through which how .
-(void)downloadimagefromserver:(UIButton *)sender
{
int index =(int) sender.tag;
historyclass *class1 = [messages objectAtIndex:index];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:arrayOfStringsfinal[1]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
}

Run request operations in loop inside operation

How can I run multiple requests inside the success block of 1 request and wait for it to finish?
[manager GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%# Response: \n%#", url, responseObject);
resultsArray = [[NSMutableArray alloc] init];
for (NSDictionary *json in [responseObject objectForKey:#"items"]) {
[self getDetails:json];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[SVProgressHUD dismiss];
}];
Where in getDetails:(id)json is the method to load the group of requests whose parameters are based on the result of the main request.
For example:
I would like to request from the API a list of students, then on the success block. For each student, I would like to get the related data from another table (another request) and put them on my NSObject.
EDIT Here is my getDetails method
- (AFHTTPRequestOperation *)getDetails:(NSDictionary *)json
{
NSLog(#"Start Op %#",[json objectForKey:#"related_salon"]);
NSString *url = [NSString stringWithFormat:#"%#read/salons/%#",SERVER_API_URL,[json objectForKey:#"related_salon"]];
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:req];
//op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success %#",[json objectForKey:#"name"]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failed Op %#",error.localizedDescription);
}];
//AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:req];
//op.responseSerializer = [AFJSONResponseSerializer serializer];
[op start];
return op;
}
The AFNetworking GET method returns a ATHTTPRequestOperation (an NSOperation subclass). You could have your getDetails method return that object. You can then create a new operation dependent upon those operations, which you'd run at the end:
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
// add here whatever you want to perform when all the getDetails calls are done,
// e.g. maybe you want to dismiss your HUD when all the requests are done.
[SVProgressHUD dismiss];
}];
[manager GET:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%# Response: \n%#", url, responseObject);
resultsArray = [[NSMutableArray alloc] init];
for (NSDictionary *json in [responseObject objectForKey:#"items"]) {
NSOperation *operation = [self getDetails:json];
[completionOperation addDependency:operation];
}
[[NSOperationQueue mainQueue] addOperation:completionOperation];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[SVProgressHUD dismiss];
}];
Again, this is presuming that getDetails is doing its own GET call, and that you change getDetails to (a) capture the NSOperation returned by GET and (b) return it.

UIProgressView+AFNetworking not updating progress

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.

AFNetworking AFHTTPRequestOperation block is never called

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];

Resources