I hope this hasn't been asked here...I've done quite a bit of searching on this site but am not really getting anywhere I've been using ASIHTTPRequest to get JSON data, but am now trying to migrate to AFNetworking 2.1.0. I'm using the following:
-(BOOL)getCoordsForAddress:(NSString*) inputAddress {
responseString = [[NSString alloc] init];
// retrieve and urlencode address
NSString *encodedAddress = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)inputAddress, NULL, (CFStringRef)#"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8);
// build the geocoding URL
NSString *getLatLonUrl = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=false", encodedAddress];
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:#"http://maps.googleapis.com"]];
manager.securityPolicy.allowInvalidCertificates = YES;
[manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[manager GET:getLatLonUrl
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
responseString = [responseObject objectForKey:#"results"];
NSLog(#" Success %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#" Fail %#", error);
}];
return YES;
}
However, when I execute the manager GET routine, nothing is executed, neither the Success or Failure messages are printed out. It's as if that call is getting ignored. What am I doing wrong? Thanks for any assistance!!!
Related
I am using AFNetworking to get a JSON response. I am getting is as a PhotoPXArray (model I created using mantle). The log output is exactly the data I want. My problem is using the data. How do I go about saving the response data as a variable that can be used elsewhere in my program.
Also, I am using Sculptor to help with serializing.
-(NSArray*) getPhotoForWord:(NSString*)word {
NSArray *results = nil;
NSString *requestString = BASE_URL;
requestString = [requestString stringByAppendingString:#"photos/search?term="];
requestString = [requestString stringByAppendingString:word];
requestString = [requestString stringByAppendingString:CONSUMER_KEY];
NSString *encoded = [requestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [SCLMantleResponseSerializer serializerForModelClass:PhotoPXArray.class];
[manager GET:encoded
parameters:nil
//success:^(AFHTTPRequestOperation *operation, id responseObject) {
success:^(AFHTTPRequestOperation *operation, PhotoPXArray *responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
return results;
}
#end
Read the Apple documentation regarding blocks and variables. Or you can view this question on SO that will probably also answer your question.
From the Apple docs:
__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or
created within the variable’s lexical scope. Thus, the storage will
survive the destruction of the stack frame if any copies of the blocks
declared within the frame survive beyond the end of the frame (for
example, by being enqueued somewhere for later execution). Multiple
blocks in a given lexical scope can simultaneously use a shared
variable.
Use a completion block to get your data out:
- (void)getPhotoForWord:(NSString *)word completionHandler:(void ^(PhotoPXArray *photoArray))completionHandler
{
NSString *requestString = BASE_URL;
requestString = [requestString stringByAppendingString:#"photos/search?term="];
requestString = [requestString stringByAppendingString:word];
requestString = [requestString stringByAppendingString:CONSUMER_KEY];
NSString *encoded = [requestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [SCLMantleResponseSerializer serializerForModelClass:PhotoPXArray.class];
[manager GET:encoded
parameters:nil
success:^(AFHTTPRequestOperation *operation, PhotoPXArray *responseObject) {
NSLog(#"JSON: %#", responseObject);
if (completionHandler) {
completionHandler(responseObject);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
Then call it like this:
[object getPhotoForWord:#"word" completionHandler:^(PhotoPXArray *photoArray) {
// Do something with photo array.
}];
Note that this call is asynchronous and will complete at some unknown time in the future. Also, you should likely take an NSError argument in the completion block so you can see if you get an error from the request, but I'll leave that to you.
I am using AFNetworking to get a JSON response. I am getting is as a PhotoPXArray (model I created using mantle). The log output is exactly the data I want. My problem is using the data. When I set a break point and look at the responseObject, it is nil. I don't know why the log is pumping out data but the value is nil in the debugger.
What I am ultimately trying to do is save the response to use it later.
Also, I am using Sculptor to help with serializing.
-(NSArray*) getPhotoForWord:(NSString*)word {
NSArray *results = nil;
__block NSMutableDictionary *test = nil;
NSString *requestString = BASE_URL;
requestString = [requestString stringByAppendingString:#"photos/search?term="];
requestString = [requestString stringByAppendingString:word];
requestString = [requestString stringByAppendingString:CONSUMER_KEY];
NSString *encoded = [requestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [SCLMantleResponseSerializer serializerForModelClass:PhotoPXArray.class];
[manager GET:encoded
parameters:nil
//success:^(AFHTTPRequestOperation *operation, id responseObject) {
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
test = responseObject;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
return results;
}
You never set results variable, so of course that will return nil. Even if you used test (which you do set), that happens asynchronously, so when you immediately return, it will be nil, too, only getting the responseObject value later.
You might consider employing an asynchronous pattern, instead, supplying a completion handler parameter:
- (void)getPhotoForWord:(NSString*)word completionHandler:(void (^)(id responseObject, NSError *error))completionHandler{
NSString *requestString = BASE_URL;
requestString = [requestString stringByAppendingString:#"photos/search?term="];
requestString = [requestString stringByAppendingString:word];
requestString = [requestString stringByAppendingString:CONSUMER_KEY];
NSString *encoded = [requestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [SCLMantleResponseSerializer serializerForModelClass:PhotoPXArray.class];
[manager GET:encoded parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completionHandler) {
completionHandler(responseObject, nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completionHandler) {
completionHandler(nil, error);
}
}];
}
You'd then call that like so:
[obj getPhotoForWord:word completionHandler:^(id responseObject, NSError *error) {
// use responseObject here
}];
// do not use it here because the above happens asynchronously (i.e. later)
It looks like you aren't assigning results to anything. The only 2 times it appears in your code is when you declared it:
NSArray *results = nil;
and when you return it:
return results;
What it appears you are missing is parsing your test dictionary and populating an array, then returning that?
But as gabbler said in the comments, the call is asynchronous so unless you set up a semaphore, notifications, or something along those lines to make it synchronous, the return has a chance to be nil anyways.
i have a request which returns information from a php web service. I'm having trouble adding this to a array which can be used in my UICollectionView. It seems like whatever i do i cant return the data. I think it is because i'm returning the array before i've added any objects. I've tried placing the NSLog several places, but without luck. What am i doing wrong?
When i place this NSLog(#"%d", imagesArray.count); beyond the request it returns 0.
ViewDidAppear:
-(void)viewDidAppear:(BOOL)animated {
imagesArray = [[NSMutableArray alloc] init];
[self getImages];
}
getImages method:
-(void)getImages {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:#"http://URL.COM" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseObject options:kNilOptions error:nil];
NSString *theTitle = [[json objectForKey:#"response"] valueForKey:#"title"];
NSString *theUrl = [[json objectForKey:#"response"] valueForKey:#"imageUrl"];
[imagesArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:
theTitle, #"title",
theUrl, #"url",
nil]];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
NSLog(#"%d", imagesArray.count);
}
AFNetworking is Asynchronous, you have to place the log inside the success block. Otherwise the array will always be empty.
One good solution would be to pass a block to your getImages function like that
-(void) getImages:(void (^)(BOOL result))callback {
// your code here then you call callback(YES or NO) inside your success or failure block.
}
[self getImages:^(BOOL result){
if(result)
//we got the images, we can now display them etc.
}];
i am really new to IOS development. i want to develop an application which is dealing with some web services and display in a table view. somehow i found a 3rd party library for do the networking stuffs [AFNetworking 2]. below is my code to get the json response for any given url and parameters.
-(NSDictionary*)getWebServiceResponce:(NSString *)url :(NSDictionary *)object
{
// NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:#"47", #"caregiverPersonId", nil];
__block NSDictionary* result=Nil;
__block NSString* person=Nil;
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager setSecurityPolicy:policy];
operationManager.requestSerializer = [AFJSONRequestSerializer serializer];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
person = [responseObject[#"d"]objectForKey:#"PersonId"];
// [self returnedResponce:responseObject];
result = (NSDictionary *) responseObject[#"d"];
NSLog(#"RESULT: %#", result);
NSLog(#"personm: %#", person);
[operation waitUntilFinished];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error description]);
//result = [error];
}
];
return result;
}
this code works perfectly.. but my point is when i put some breakpoints to check what are the values i got for several variables, it shows null. but my log shows the entire json response.
and i want to return my response object as a dictionary. because i want to do some process with the response.. can some one help me with this ?
The problem is that result is nil when it gets returned. AFNetworking uses ObjC's awesome blocks, they get executed asynchronously. Read more about it here.
You should include a callback block in your getWebServiceResponce method. I've thrown together a bit of code but you should really read more about blocks.
-(void)webServiceResponceForURL:(NSString *)url dictionary:(NSDictionary *)object success:(void (^)(NSDictionary *responseObject))success {
// NSDictionary *parameters = [[NSDictionary alloc] initWithObjectsAndKeys:#"47", #"caregiverPersonId", nil];
__block NSDictionary* result=Nil;
__block NSString* person=Nil;
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
[operationManager setSecurityPolicy:policy];
operationManager.requestSerializer = [AFJSONRequestSerializer serializer];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager POST:url
parameters:object
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
person = [responseObject[#"d"]objectForKey:#"PersonId"];
// [self returnedResponce:responseObject];
result = (NSDictionary *) responseObject[#"d"];
NSLog(#"RESULT: %#", result);
NSLog(#"personm: %#", person);
//We are executing the block as soon as we have the results.
if (success) {
success(responseObject);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error description]);
//result = [error];
}
];
}
Edit:
[self webServiceResponceForURL:#"foo://foo" dictionary:nil success:^(NSDictionary *responseObject) {
//your code here
}
[self webServiceResponceForURL:#"foo://foo" dictionary:nil success:^(NSDictionary *responseObject) {
//your code here
}
Here you will got complete responseObject in form NSDictionary. You can assign responseObject to instance variable. Now This instance Variable will be used at point time. in your case, it will passed on button event.
hi i need to send a array as a one of the parameter in Afnetworking Query String
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://192.008.0.28/aaa/a/"]];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: #"20", #"Miles", [NSArray arrayWithObjects:#"1",#"2",#"3",nil], #"Interval", nil];
[httpClient postPath:iUpdateNotificationMethod parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *responseStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Request Successful, response '%#'", responseStr);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"[HTTPClient Error]: %#", error.localizedDescription);
}];
But server side we got "Miles":20,"Intervals":null how to fix it
Thanks,
Try This
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:OAuthBaseURL];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] initWithCapacity:0];
for (int i =0; i < [userIDs count]; i++) {
NSString *userID = [[userIDs objectAtIndex:i] objectForKey:#"id"];
NSDictionary *tmpDict = [NSDictionary dictionaryWithObjectsAndKeys:userID , [NSString stringWithFormat:#"ids[%i]",i], nil];
[parameters addEntriesFromDictionary:tmpDict];
}
[client postPath:#"/user"
parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSData *data = (NSData *)responseObject;
NSString *jsonStr = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(#"jsonStr %#",jsonStr);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self showError];
}
];
Since you're submitting an array, AFNetworking is generating a different parameter name and overloads it with the values you supply. For example, your request generates the following querystring:
Interval[]=1&Interval[]=2&Interval[]=3&Miles=20
This is defined in AFHTTPClient.m in the AFQueryStringPairsFromKeyAndValue function.
If you want to keep the original parameter, you should decide how to convert your NSArray to NSString by yourself. For example, you can do something like [myArray componentsJoinedByString:#","] and then split it back to elements on the server. If you choose this method, beware of using characters that might appear in your actual data.
I believe this will work:
params = #{ #"Miles": #"20", #"Interval": #[#"1",#"2",#"3"] };