Objective C Accessing Elements - ios

I'm attempting to obtain elements extracted from a dictionary and convert them to doubles. The data is being pulled from JSON and seems to be extracted into a type of array (not sure which type). Is there a way to obtain the numbers listed below individually out of the array? Please let me know if you need more information.
NSDictionary *parameters = #{#"username":savedUser,#"password":savedPass};
NSURL *URL = [NSURL URLWithString:#"testwebsite"];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:URL.absoluteString parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject)
{
NSError *error = nil;
JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
if (error) {
NSLog(#"Error serializing %#", error);
}
NSLog(#"%#",JSON);
NSString *price = [NSString stringWithFormat:#"%#",[JSON valueForKey:#"UnitPrice"]];
price= [price stringByReplacingOccurrencesOfString:#"\"" withString:#""];
NSLog(#"Price: %#",price);
[transactionTotals addObject:price];
[self createGraph:100];
}
failure:^(NSURLSessionTask *operation, NSError *error)
{
NSLog(#"Error1: %#", [error debugDescription]);
NSLog(#"Error2: %#", [error localizedDescription]);
}];
}
#catch (NSException *exception)
{
NSLog(#"%#",exception);
}
Log (UnitPrice values I need individually extracted):
Dictionary output:
2016-07-03 22:52:21.330 T2PApp[2272:658440] (
{
OrderDetailID = 3;
ProductName = Oranges;
UnitPrice = "399.99";
date = "2016-06-09T21:45:06";
},
{
OrderDetailID = 7;
ProductName = Oranges;
UnitPrice = 1000;
date = "2016-06-13T22:15:47.107";
}
)
Extracted UnitPrice output (still not completely extracted):
2016-07-03 22:52:21.330 T2PApp[2272:658440] Price: (
399.99,
1000
)

I think what you need is digging out the data from the objects in array. It not about the JSON.
There is many way to do it, but not one simply way to dig it out.
For example, create a new array, and traverse the target array, put the property you need into the new array.
It is basically like that.
In your code, maybe the code below will work.
NSLog(#"%#",JSON);
NSMutableArray *priceArr = [NSMutableArray array];
NSArray *arr = nil;
if ([JSON isKindOfClass:[NSArray class]]) {
arr = (NSArray *)JSON;
for (NSDictionary *dic in arr) {
NSString *price = [NSString stringWithFormat:#"%#",[dic valueForKey:#"UnitPrice"]];
price= [price stringByReplacingOccurrencesOfString:#"\"" withString:#""];
[priceArr addObject:price];
}
}
priceArr is what you need.

Related

Google Place Search API in IOS

I have implemented the google place search API in IOS and enabled the API in the developer console and used the below code but its shows error that "This IP, site or mobile application is not authorized to use this API key. Request received from IP address 122.173.223.114, with empty refer"
After regenerate the API key its shows API key is expired and after sometime its shows the same above errors. Please help someone.
-(void) queryGooglePlaces: (NSString *) googleType {
// Build the url string to send to Google. NOTE: The kGOOGLE_API_KEY is a constant that should contain your own API key that you obtain from Google. See this link for more info:
// https://developers.google.com/maps/documentation/places/#Authentication
NSString *url = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=%#&types=%#&sensor=true&key=%#", appDel.objLocationManager.location.coordinate.latitude, appDel.objLocationManager.location.coordinate.longitude, [NSString stringWithFormat:#"%i", appDel.currenDist],googleType, kGOOGLE_API_KEY];
//Formulate the string as a URL object.
NSURL *googleRequestURL=[NSURL URLWithString:url];
// Retrieve the results of the URL.
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
}
-(void)fetchedData:(NSData *)responseData {
//parse out the json data
if (responseData==nil) {
}else{
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
//The results from Google will be an array obtained from the NSDictionary object with the key "results".
NSArray* places = [json objectForKey:#"results"];
//Write out the data to the console.
NSLog(#"Google Data: %#", json);
}
}
I did it with use of AFNetworking class Try this one,
#define kGoogleAutoCompleteAPI #"https://maps.googleapis.com/maps/api/place/autocomplete/json?key=%#&input=%#"
-(void)getAutoCompletePlaces:(NSString *)searchKey
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// set request timeout
manager.requestSerializer.timeoutInterval = 5;
NSString *url = [[NSString stringWithFormat:kGoogleAutoCompleteAPI,GoogleDirectionAPI,searchKey] stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSLog(#"API : %#",url);
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"JSON: %#", responseObject);
[MBProgressHUD hideHUDForView:self.view animated:YES];
NSDictionary *JSON = responseObject;
predictions = [NSMutableArray array];
// success
AutomCompletePlaces *places = [AutomCompletePlaces modelObjectWithDictionary:JSON];
[arrSuggestionData removeAllObjects];
if (!arrSuggestionData) {
arrSuggestionData = [NSMutableArray array];
}
for (Predictions *pred in places.predictions)
{
[arrSuggestionData addObject:pred.predictionsDescription];
}
[self.Tbl_suggestion reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %#", error);
}];
}

Using AFHTTPRequestOperation to construct URL (curly braces included)

I need to construct URL like this using AFNetworking the problem for me it's { and } how to pass throught parameter
/api/sth.json?filter[condition]={"53891":[123],"53892":[123,124]}
So my code looks like this (i made it simpler):
[self GET:myUrl parameters:#{
#"filter" : #{
#"condition" : #{
#"53891" : #[#(123)],
#"53892" : #[#(123),#(124)]}
},
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
success(operation,responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure(operation,error);
}];
But it's produce not expected output:
/api/sth.json?filter[condition][53891][]=123&filter[condition][53892][]=123&filter[condition][53892][]=124
There is a way to do this in parameters in AFHTTPRequestOperation or manually i have to put it into string?
EDIT:
My current solution is like that:
+(NSString*)convertFromDictionary:(NSDictionary*)dic {
NSMutableString *outputStr = [NSMutableString new];
[outputStr appendString:#"{"];
NSArray *allKeys = [[dic allKeys] sortedArrayUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:nil ascending:NO]]];
for(NSString *key in allKeys) {
NSArray *objects = dic[key];
[outputStr appendString:[NSString stringWithFormat:#"\"%#\":[",key]];
for(NSNumber *nb in objects) {
[outputStr appendString:[NSString stringWithFormat:#"%li",[nb longValue]]];
if(![nb isEqual:[objects lastObject]]) {
[outputStr appendString:#","];
} else {
[outputStr appendString:#"]"];
}
}
if(![key isEqual:[allKeys lastObject]]) {
[outputStr appendString:#","];
}
}
[outputStr appendString:#"}"];
return outputStr;
}
Where input dictionary is:
#{#"53892" : #[#(123),#(124)]}
But it's nothing more than string compare. There is no more clever way to achieve it with AFNetworking directly since it's fairly standard URLs parameters?
You want 2 different ways of parsing a dictionary, and this cannot be done automatically. As Mehul said before, try serializing your parameter "condition" (converting its value to string) before creating the "parameters" dictionary:
NSError *error;
NSDictionary *dict = #{#"53891" : #[#(123)], #"53892" : #[#(123),#(124)]};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
NSString *params = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[self GET:myUrl parameters:#{
#"filter" : #{
#"condition" : params
},
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
success(operation,responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure(operation,error);
}];
You need to do this:
create dictionary
create json string from dictionary(first convert dictionary to NSData using NSJsonSerialization and then convert thata NSData object to NSString)
Now append this string in your URL in format which you want to attach to
create url from new string and pass it in get/post method with paramters dictionary as nil
Wrapping a numbers with parenthesis is for expressions :
#(6 + x * 2012)
Read excellent explanation post https://stackoverflow.com/a/9349981/3096087
Maybe wrapping in parenthesis somehow messes up with AFHTTPRequestOperation.
NSNumber are directly declared the following way :
NSNumber *number = #123;
So try with an input dictionary the following way :
#{#"53892" : #[#123,#124]}

AFNetworking request returns nil

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

Issue with AFNetworking

My client webservice send me a result like this:
{"login":{"EMAIL":"none","ID":"none","NOME":"none"}}
So, in AFN doesn't work.
But, if have one more result works:
{"login":[{"EMAIL":"none","ID":"none","NOME":"none"},{"EMAIL":"none","ID":"none","NOME":"none"}]}
My code:
NSDictionary *paramLogin = [NSDictionary dictionaryWithObjectsAndKeys:_txtEmail.text, #"email",_txtSenha.text, #"senha", nil];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://webservice.info" parameters:paramLogin success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#" , responseObject );
for (NSDictionary *retLogin in [responseObject valueForKeyPath:#"login"]) {
nome = [retLogin objectForKey:#"nome"];
email = [retLogin objectForKey:#"email"];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
why it is like this? or what I've to do ?
Sometimes [responseObject valueForKeyPath:#"login"] returns and array, sometimes it returns a dictionary. You need to test for this.
id loginValue = [responseObject valueForKeyPath:#"login"];
if ([loginValue isKindOfClass:[NSDictionary class]]) {
nome = [loginValue objectForKey:#"nome"];
email = [loginValue objectForKey:#"email"];
} else if ([loginValue isKindOfClass:[NSArray class]]) {
for (NSDictionary *retLogin in [responseObject valueForKeyPath:#"login"]) {
nome = [retLogin objectForKey:#"nome"];
email = [retLogin objectForKey:#"email"];
}
} else {
// ERROR: Unexpected value
}
When you have 1 value, then loginValue is an NSDictionary. It contains {"EMAIL":"none","ID":"none","NOME":"none"}.
When you have more than 1 value, then loginValue is an NSArray. The array contains [<NSDictionary>, <NSDictionary>]. Each of of these dictionaries contains {"EMAIL":"none","ID":"none","NOME":"none"}.
Problem is with your json data structure. It's not consistent.
{"login":{"EMAIL":"none","ID":"none","NOME":"none"}}
Here [responseObject valueForKeyPath:#"login"] is a single NSDictionary object.
But here,
{"login":[{"EMAIL":"none","ID":"none","NOME":"none"},{"EMAIL":"none","ID":"none","NOME":"none"}]}
Here [responseObject valueForKeyPath:#"login"] is an NSArray. So your fast enumeration works.
Best solution is to ask your webservice developer to send an array all the time, even 'login' has a single object. so it should look like this,
{"login": [{"EMAIL":"none","ID":"none","NOME":"none"}]} //notice square brackets
Otherwise you have to modify your code to check for an NSDictionary instead of array when there's only one object.
I suspect the issue is that you aren't retaining the AFHTTPRequestOperationManager object.
Assuming this code is in something like viewDidAppear:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:...];
Then manager will be destroyed before it has a chance to complete.
Instead add a property and store the manager object in that:
#interface MyViewController ()
#property (nonatomic) AFHTTPRequestOperationManager *manager;
#end
and use:
self.manager = [AFHTTPRequestOperationManager manager];
[self.manager GET:...];
if you are getting response like that than use below code
NSMutableArray *category = [[NSMutableArray alloc]init];
category = [responseObject objectForKey:#"login"];
for(int i = 0; i < [category count]; i++)
{
NSDictionary *dic = [category objectAtIndex:i];
nome = [dic objectForKey:#"nome"];
email = [dic objectForKey:#"email"];
}

AFHTTPRequestOperationManager JSON data to Array

I'm using AFNetworking 2.0 to make a POST request to my web service that returns JSON data.
{
post = {
"first_name" = Joe;
"last_name" = Blogs;
"user_id" = 1;
};
},
{
post = {
"first_name" = Bill;
"last_name" = Gates;
"user_id" = 2;
};
}
Im able to print out responseObject to the console fine which displays my JSON data.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"user": #"root"};
[manager POST:#"http://192.168.0.100/webservice.php" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *responseString = [operation responseString];
NSError *error;
NSArray *json = [NSJSONSerialization
JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding]
options:kNilOptions
error:&error];
for (NSDictionary *dictionary in json)
{
NSString *firstName = [[dictionary objectForKey:#"post"] valueForKey:#"first_name"];
NSLog(#"%#", firstName);
NSString *lastName = [[dictionary objectForKey:#"post"] valueForKey:#"last_name"];
NSLog(#"%#", lastName);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %#", error);
}];
Each "post" is going to be used for a table cell on my View Controller. Im struggling to understand how to make each post an object in an array. Any help appriciated.
UPDATE
You can use this code snipped to perform your desired functionality:
NSString *responseString = [operation responseString];
NSData *data= [responseString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSArray* results = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
for (int i=0; i<results.count; i++)
{
NSDictionary *res=[results objectAtIndex:i];
NSDictionary *res2=[res objectForKey:#"post"];
[self.storesArray addObject:res2];
}
[self.tableView reloadData];
and in your CellForRowAtIndexPath method, use this code snipped to show data on your cell:
NSDictionary *res=[self.storesArray objectAtIndex:indexPath.row];
cell.firstName.text=[res objectForKey:#"first_name"];
cell.lastName.text=[res objectForKey:#"last_name"];
This NSDictionary works in key values pair style, so you can get the value of any key by just mentioning the key name and get the values of that key.

Resources