Variable not changed by AFNetworking GET function - ios

I am trying to use an AFNetworking class to retrieve data from a database. Long story short, the data received from the parameter responseObject is filled with items. Here is my problem however. I am trying to copy the results in responseObject into an NSDictionary called results. I used the following code to get there:
__block NSDictionary *results;
[manager GET:#"http://daneolog.altervista.org/app/getData.php"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) { results = responseObject;
NSLog(#"Inside: %#", results); }
failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(#"%#", error); }];
NSLog(#"Outside: %#", results);
I tried NSLoging the results dictionary INSIDE the success braces, and everything is a-okay there.
I tried NSLoging the results dictionary OUTSIDE the GET function, and it comes up as (null).
These are my results:
2015-11-12 14:34:34.875 TestApp[4864:258743] Outside: (null)
2015-11-12 14:34:35.242 TestApp[4864:258743] Inside: (
{
address = "Sample Address";
}
)
Now notice the peculiar thing: the outside NSLog is being executed first. I don't know why this is so. Can anyone help me on this? Thanks a bundle.

Your code outside the success block is executing before the success block completes that is why results come up as null. results is on the main thread, and you are not blocking (as is correct with an HTTP request).
You can pass a weak reference to an object, and have that updated. Or if you absolutely need to wait for the result (login for instance) then you should do it on the main thread.
Here is an example of a weak object:
//results is an object created earlier
__weak NSDictionary *weakResults = results;
[manager GET:#"http://daneolog.altervista.org/app/getData.php"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
weakResults = responseObject;
NSLog(#"Inside: %#", results);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%#", error);
}];
//when the success block finishes the results object will be populated
If you wanted to block i.e. do it on the main thread you could use:
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
However, if the response doesn't come back, your app hangs.

Related

Method with completion handler

I've created a method in a class:
- (void)getTableData:(NSString *)URL withCompletionHandler:(void (^)(NSString *))handler{
__block NSDictionary *JSON;
[manager POST:urlString parameters:jsonDict success:^(AFHTTPRequestOperation *operation, id responseObject){
JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
handler(JSON);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error %#",error);
// handle failure
}];
}
and call it in another class by
[ObjOfSecondClass getTableData:BILL withCompletionHandler:^(NSString* returnString)handler{
}];
It shows Expected expression error at handler.
It's an expression error because you are using it in wrong way.
Try this one in viewDidLoad
[ObjOfSecondClass getTableData:BILL withCompletionHandler:^(NSString* returnString){
}];
handler is used is block implementation to return value from where they are called.
Note - replace string to dictionary in block definition because you are getting dictionary from API not string.
Learn block syntax

AFNetworking View JSON Content For Error Code 3840

I am working on an app where I have AFNetworking fetching JSON requests from the my server. Now JSON is dynamically created based upon the POST variables I send from my app.
I was wondering when I get the following error message
JSON text did not start with array or object and option to allow fragments not set.
Is there a way to adapt my code so that I can actually see in the logger what the returned JSON request looks like. I have a feeling that there is a warning popping up in my PHP that is throwing off the JSON but I am not sure what it is.
Here is my code, it would make it so much easier if I could lets say NSLog the body content.
[manager POST:#"__MY__URL__" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
} progress:nil success:^(NSURLSessionDataTask *operation, id responseObject) {
NSLog(#"Success: %#", responseObject);
if([[responseObject objectForKey:#"state"] isEqualToString:#"success"]){
//[self performSegueWithIdentifier:#"client_choose_ad" sender:self];
}else {
[self alertError:#"Unable To Create Advert" alertMessage:[responseObject objectForKey:#"message"]];
}
} failure:^(NSURLSessionDataTask *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Maybe printing the raw data of the request is what you are looking for.
How to print AFNetworking request as RAW data

Value of NSMutableDictionary is not changing inside the block

I am passing the URL in this method and getting the data as output. i want to assign a new value to nsmutabledictionary but it is not assigning the value.
-(NSDictionary*) getDatafromURL: (NSString*)url{
__block NSMutableDictionary *returnData=[[NSMutableDictionary alloc] init];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
returnData=(NSMutableDictionary*)responseObject;
NSLog(#"Data 1: %#",returnData);// it is printing the data
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
NSLog(#"Data 2: %#",returnData);// it is not printing any data
return returnData;
}
in this above example the Data 1 is showing value successfully
Data 2 gives me empty dictionary.why it is not assigning the new value?
That happens because you get to the line with "Data 2" first and the block is executed only afterwards, since it is an async request. I would suggest that you change your method to something like:
- (void)getDataFromURL:(NSString *)url completionHandler:(void (^)(NSMutableDictionary *returnData, NSError *error))handler {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
returnData=(NSMutableDictionary*)responseObject;
NSLog(#"Data 1: %#",returnData);// it is printing the data
handler(returnData, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
handler(nil, error);
}];
}
There might be some compile errors in the code I provided.
The other solution would be to do a synchronous request, in which case the block would be executed before the code that is after the block.
EDIT:
If you are choosing the first solution, you have to continue using it asynchronously. So you would call it like:
[self getDataFromURL:#"abc.com" completionHandler:^ (NSMutableDictionary *returnData, NSError *error) {
// process your dictionary and the error object
}];
Please check whether your Data 2 is printing before data 1? If yes, its because, the response object gets downloaded only after a certain delay. Take away the return statements. Pass the data to the dictionary to which you return the method. For eg: like
instead of
self.myDictionary = [self getDatafromURL:someURl];
to
-(void) getDatafromURL: (NSString*)url{
__block NSMutableDictionary *returnData=[[NSMutableDictionary alloc] init];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
returnData=(NSMutableDictionary*)responseObject;
NSLog(#"Data 1: %#",returnData);// it is printing the data
self.myDictionary = returnData;
// Continue whatever you want to do
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Or use the dispatch methods instead of the blocks.
like
Or use manager waitUntilFinish method below.

How do I use a variable outside of a GET request?

I would like to:
Initialise a variable prior to an GET request (AFNetworking)
Assign to the variable inside the request success
Use the variable once request is done
The error I get:
When trying to do something the variable after the GET request, it breaks, claiming there is no value to the variable yet
The following is my code, how do I solve this problem?
- (IBAction)synchronisePressed {
//Would like to initialise a variable here
__block NSArray *received;
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://foo.com/foo/"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
//Assign responseObject to received object
received = responseObject;
NSLog(#"Woo: %#", #"got here");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
//Now outside of request, so use array in some way
[foo received];
}
The problem is not in the code or in the request. The problem is the GET method of AFNetworking is asynchronous and you are trying to use it synchronously.
This means that the GET method will start working and sit in the background working away and the rest of your code will continue as normal. Only when the GET request has finished will the code inside the blocks get run.
This code be 1 second or 30 seconds or any amount of time after you start the request.
Put in an NSLog before your line [foo received];.
The order of logs will be like so...
1. Created NSArray called received.
2. Pass NSArray called received to method foo.
// some time later
3. AFNetworking GET request finished.
4. Assign value from the GET request to the NSArray called received.
What you need to do in this case is put your call to [foo received]; INSIDE the completion block.
Something like this...
- (IBAction)synchronisePressed
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://foo.com/foo/"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
//Assign responseObject to received object
NSArray *received = responseObject;
NSLog(#"Woo: %#", #"got here");
[foo received];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Now you will get...
1. Created NSArray called received.
// some time later
2. AFNetworking GET request finished.
3. Assign value from the GET request to the NSArray called received.
4. Pass NSArray called received to method foo.

Passing JSON object received asynchronously in block to an instance variable - using AFNetworking on iOS6

This code has the JSON but no matter what I do I haven't been able to figure out how to pass this JSON to an instance variable. Each time I set it to a variable and call that variable outside of this method its nil. So what I can gather is that the variable is called before the following async call returns.
So the question is what can I do to the following code so that I can extract the JSON value. Somewhere on the internet I read that I would need to pass it a block which would server as a call back on completion but I cannot figure out how to do that for the following code
//Gets the JSON object that contains the entries from the server
-(void)getEntriesFromServer
{
NSLog(#"%s", __PRETTY_FUNCTION__);
[[appAPIClient sharedClient] getPath:#"/entries"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id JSON)
{
NSLog(#" JSON array = %#",[JSON valueForKeyPath:#"entries"]);
}failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#" Json not received");
}];
}
Thanks
try to add __block to definition of an array e.g __block NSArray* entriesArray;
or make a property like
#property (nonatomic, retain) NSArray* entriesArray;
and change your code like this
[[appAPIClient sharedClient] getPath:#"/entries"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id JSON)
{
//NSLog(#" Json value received is : %# ",[JSON description]);
//NSLog(#" JSON array = %#",[JSON valueForKeyPath:#"entries"]);
self.entriesArray = [NSArray arrayWithArray:[JSON valueForKeyPath:#"entries"]];
NSLog(#" JSON array from inside block = %#", _entriesArray);
}failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#" Json not received");
}];
Hope it'll help

Resources