I am developing simple app in iOS that gets data web api my code returned json data correctly but when I want to specific for example student name from json returned null.
Here is my data :
{
Sudent(
{
{"id":"20",
"name":"Alan",
"email":"simpl#gmail.com",
"phone":"1234567890",
"location":"London"},
{
"id":"40",
"name":"John",
"email":"simpl#gmail.com",
"phone":"1234567890",
"location":"usa"},
"id":"50",
"name":"Nora",
"email":"simpl#gmail.com",
"phone":"1234567890",
"location":"kenya"},
})}
Here my code that gets data as json and stored NSMutableArray named Student:
-(void)proxydidFinishLoadingData:(id)data InMethod:(NSString*)method
{
if ([method isEqualToString:#"getstudentdata"]){
defaultDict = [[NSMutableDictionary alloc]init];
[defaultDict addEntriesFromDictionary:[NSJSONSerialization JSONObjectWithData:[data dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]];
Student = [defaultDict objectForKey:#"data"];
}
}
this codes it works ok and correctly and returned json data but the problem is when I want to get specific index such as names of students it is not work it returns null value.
the code that does this work is here:
NSMutableDictionary *response = [[defaultDict valueForKey:#"data"] mutableCopy];
NSString *name = [[response valueForKey:#"name"]];
];
NSLog(#"%#" ,name);
Please help me this to get student names
You are checking "name" key in "data" key, but in fact it is present in "Student" key.
Parse to Student object and using for loop get one by one "name" key value.
Use this site http://www.json4swift.com/ to create Model.(Just you have to Put JSON response here).
Var dataModelArray = [Your_Model_Type]()
if let data = data[“student”] as? [String: AnyObject] {
dataModelArray = Your_Model_type.modelsFromDictionaryArray(array: data)
}
//And you will have array of data in your dataModelArray
//Example you can access like this
dataModelArray[0].name
Related
So I was working on a project that required me to work with some JSON, I was running into a few issues regarding the best way of representing things. First of, this is how the JSON looks:
"phoneList": [
{
"phoneReason": "End of Contract",
"phoneType": [
{
"id": 5,
"phoneType": "Android Smartphone"
}
]
}
]
I want to know the most appropriate way of representing this.
For example, I do know that that my phoneReason will just be a simple NSString while my phoneType is actually a NSArray. However,I wasn't sure how to represent a)the id, I know this is an integer, but should this be an NSInteger or an NSNumber and b)could someone point me in the direction of some sample code where I can understand how to model a dictionary object containing an integer and a string and also where I can understand how to model an array of dictionaries.
My other question is also similar in that say I'm actually posting something, how do I model this, specifically say for like dictionary type (JSON Curly Brace)objects that contain a number/integer and a string.
For example, this is the JSON I'm trying to model and then do something like this:
"phoneReason": "Upgrade",
"phoneInfo": {
"id": "2"
},
//And then I want to pass ID
-(void) createOurRequest:(NSNumber *)id {
NSDictionary *myDictionary = #{
#"phoneReason" : [NSString stringWithFormat:#"%i", s elf.dat.reason],
//How do I then represent the phoneInfo element exactly?
};
Sorry, for the clumsy question, would really appreciate any guidance on modeling JSON in iOS or just generally.
I'm assuming you're asking questions a) and b), and also how to model a JSON.
a) The unfortunate thing with Obj-C is that all collection elements have to be objects. Integers are value types, so they will need to be converted to NSNumbers to work. However, if you're parsing a JSON string, the builtin JSON parser does it for you. I'll describe it below.
b) The model is based on the JSON. You describe the object collection and the parser will determine the model for you. In your example, you would have a NSDictionary<NSString *: NSArray<NSDictionary<NSString *: id>*>*>. The innermost element has value of id because you can either have an NSString ("End of Contract") or an NSArray ("phoneType": [ { "id": 5, "phoneType": "Android Smartphone" } ])
Of course, the model is defined by your JSON, so if you run it through a parser, you get a structured object. You can access each element based on your model (object[#"phoneList"][#"phoneReason"]).
The class method to use is:
+ (id)JSONObjectWithData:(NSData *)data
options:(NSJSONReadingOptions)opt
error:(NSError **)error
Where you pass it a NSData representation of your string, options (or 0), and a NSError pointer (error*). You get back a parsed JSON with the proper structure you defined.
NSDictionary *parsedJSONObject = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:NULL
I have no options to use and I know there will be no error, so I pass nothing for those parameters. The resulting object will be in whatever structure your JSON is.
Using the objects and the json layout you provided in your first example, this is how I would go about creating the dictionaries and arrays to get the json in the format you specified. Hopefully this helps make it a little clearer for you.
// example constructor method
-(void) jsonStringWithPhoneReason:(NSString*)reason phoneId:(NSInteger)phoneId phoneType:(NSString*)phoneType
{
// create device detail dictionary
NSDictionary *deviceOneDetail = #{
#"id" : #(phoneId), // <- set phone id as NSNumber
#"phoneType" : phoneType // <- set your string phone type
};
// create device dictionary
NSDictionary *deviceOne = #{
#"phoneReason" : reason, // <- set your phone reason string
#"phoneType" : #[deviceOneDetail] // <- set your phone type dictionary within an array
};
// create phone list dictionary with any device dictionaries you want to add
NSDictionary *phoneListDict = #{
#"phoneList" : #[
deviceOne, // <- add your device to the phone list array of dictionaries
// deviceTwo...
]
};
NSString *jsonString = [self convertToJsonString:phoneListDict]; // <- convert the dictionary into a json string and use however you wish
// your json string should now look like this assuming you pass 'End of Contract', 5 & 'Android Smartphone' as arguments to this method
// {"phoneList":[{"phoneReason":"End of Contract","phoneType":[{"id":5,"phoneType":"Android Smartphone"}]}]}
}
-(NSString*) convertToJsonString:(NSDictionary*)dictionary
{
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
options:0 // Pass 0 if you don't care about the readability of the generated string
error:&error];
if (error)
{
NSString *errorDesc = [NSString stringWithFormat:#"Error creating json data from dictionary: %#", error.localizedDescription];
NSLog(#"ERROR: %#", errorDesc);
jsonData = nil;
return nil;
}
NSString *returnString = nil;
if(jsonData != nil)
{
returnString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return returnString;
}
I have the json value like this ,
{
"product_color" = Black;
"product_description" = "The new Macbook air is ultraslim";
"product_id" = 1;
"product_large_image_url" = "https://www.gstatic.com/webp/gallery3/3_webp_ll.png";
"product_name" = "MacBook Air";
"product_price" = "$2500";
"product_size" = Small;
"product_stocks" = 50;
"product_thumb_image_url" = (
"https://www.gstatic.com/webp/gallery3/2_webp_ll.png",
......
......
);
}
and I want to insert the product_thumb_image_url array in a single attribute through core data,
what i have tried is:
+(void)insertingProduct: (int16_t) cId :(NSDictionary *)dictionary{
DataModel *dModel = [self dataModel];
Products *productDetails=[dModel createEntity:products];
productDetails.product_id=[[dictionary valueForKey:productid] integerValue];
productDetails.product_large_image_url = [dictionary valueForKey:productlargeImage];
productDetails.product_name=[dictionary valueForKey:productname];
productDetails.product_price=[[dictionary valueForKey:productPrice] integerValue];
productDetails.product_sizes=[dictionary valueForKey:productsizes];
productDetails.product_stocks=[[dictionary valueForKey:productstocks] integerValue];
productDetails.product_colors=[dictionary valueForKey:productcolors];
productDetails.product_description=[dictionary valueForKey:productdescription];
productDetails.product_thumb_image_url=[dictionary valueForKey:productThumbImage];
[dModel save];
}
but it shows that you can't insert an NSArray into an NSString, i am struggling to fix this ,
From your question, product_thumb_image_url is a String attribute in Core Data and [dictionary valueForKey:productThumbImage] returns an NSArray of URL strings from your incoming JSON.
So productDetails.product_thumb_image_url=[dictionary valueForKey:productThumbImage]; tries to store an array as a string, which obviously ins't possible.
You either need to store an Array in Core Data, which is done by making the attribute transformable, or you need to store only one image URL, which would be done by taking only the first item from the array (you should check that the array contains some items):
[[dictionary valueForKey:productThumbImage] firstObject]
I have a JSON array(dictionary?) of objects that are themselves an array. I need to find a value within one of these arrays so that I can compare it later. Part of my JSON data:
[
{
"Name": "Exhibitor",
"Url": "api/congress/exhibitor",
"ResourceType": "Data",
"LastMod": 1389106977
},
{
"Name": "Workshop",
"Url": "api/congress/workshop",
"ResourceType": "Data",
"LastMod": 1389106977
},
{
"Name": "Speaker",
"Url": "api/congress/Speaker",
"ResourceType": "Data",
"LastMod": 1389106977
},
]
My method receives a table name as a parameter and returns a time stamp. How would I receive the time stamp (1389106977) for the table "workshop" for example? This seems so simple but I cannot work it out for 'nested' arrays/dictionaries.
Thanks,
edit:
This is the my code with trojanfoe's added to it.
NSError* localError;
NSMutableArray *syncDataArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if (syncDataArray)
{
NSNumber *lastMod = nil;
for (NSDictionary *dict in syncDataArray)
{
NSLog(#"current table is: %#", dict[#"Name"]);
if ([tableName isEqualToString:dict[#"Name"]])
{
lastMod = dict[#"LastMod"];
//break;
}
}
NSLog(#"LastMod = %#", lastMod);
}
else
{
NSLog(#"syncDataArray is empty");
}
This works perfectly and makes sense
The JSON data looks like an array of dictionaries, so you can iterate over the array and test for the "Name" entry:
NSArray *jsonData = ...; // You have converted JSON to Objective-C objects already
NSNumber *lastMod = nul;
for (NSDictionary *dict in jsonData) {
if ([#"Workshop" isEqualToString:dict[#"Name"]]) {
lastMod = dict[#"LastMod"];
break;
}
}
if (lastMod) {
// You found it
}
(Note I am not certain the type of object used to store the "LastMod" object, so you might need to do some debugging to find out).
EDIT If you make extensive use of this data you should immediately convert the JSON data into an array of (custom) model objects, which will make it easier to manipulate the data as your app becomes more complex.
You have an array for dictionaries so it would look something like :
NSNumber *timestamp = [[JSON objectAtIndex:index] objectForKey:#"LastMod"];
NSNumber *timestamp = response[1][#"LastMod"];
I make a request to the Instapaper API, and it's supposed to return JSON. It returns something close to JSON, but not completely, like follows:
2013-05-30 19:54:20.155 --[53078:c07] (
{
type = meta;
},
{
"subscription_is_active" = 1;
type = user;
"user_id" = --;
username = "--#gmail.com";
},
{
"bookmark_id" = 387838931;
description = "";
hash = YHwQuwhW;
"private_source" = "";
progress = 0;
"progress_timestamp" = 0;
starred = 0;
time = 1369954406;
title = "Adobe Finally Releases Kuler Color-Picking App for iPhone - Mac Rumors";
type = bookmark;
url = "http://www.macrumors.com/2013/05/30/adobe-finally-releases-kuler-color-picking-app-for-iphone/";
},
How do I then process this? Can I take it and turn it into an NSDictionary even though it doesn't seem to be valid JSON?
From Instapaper API Docs:
Instapaper strings are always encoded in UTF-8, and Instapaper expects all input to be in UTF-8.
Unless otherwise noted, output from every method is an array. The output array is returned as JSON by default.
You can specify a jsonp parameter with a callback function name, e.g. jsonp=myCallback, to use JSONP and wrap the output in a call to the specified function.
So there is no way you will get not valid JSON!
Try following code:
NSData *jsonData = [[NSString stringWithContentsOfURL:[NSURL urlWithString:#"http://your-instapeper-API-link"] encoding:NSUTF8StringEncoding error:nil] dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
id serializationJSON = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
And then you can log what is wrong or if result is what you expect:
NSLog(#"class of JSON input: %# \n and possible error: %#",[serializationJSON class],error);
Of course you should expect Array and no error.
EDIT ... based on coment code:
Based on docs you should get Array or Dictionary. Please add this core instead your line #23 (numer from here):
if([JSON isKindOfClass:[NSDictionary class]]) {
NSDictionary *jsonDictionary = JSON;
NSLog(#"%#",[jsonDictionary allKeys]);
} else {
NSLog(#"JSON object class: %#",[JSON class]);
}
and please show us output.
One more thing:
You get array from request. Great! This is a valid JSON. So you need to debug it. As i said it's a shame is not a unlimited acccess public API, so i can look into it. But now you have to debug your result. I see in your code that you are trying to access bookmarks. So i look into Bookmarks section in docs and this is some kind of list (NSArray). So if you don't know what result you want. You should print them into log (or set a breakpoint). Replace code from my earlier update with this simple log:
NSDictionary *resultDictionary;
if([JSON isKindOfClass:[NSArray class]]) {
NSArray *jsonArray = JSON;
NSLog(#"so json is an array with %i objects",[jsonArray count]);
for(id objectInsideArr in jsonArray) {
NSLog(#"object in array [class]: %# [value]: %#",[objectInsideArr class],objectInsideArr); //if here you find NSDictionary maybe is this dictionary you are looking for. I'm not sure what it is.
if([objectInsideArr isKindOfClass:[NSDictionary class]]) {
resultDictionary = [[NSDictionary alloc] initWithDictionary:objectInsideArr];
}
}
}
If it were me I would write a custom formatter to get it into JSON format and then use NSJSONSerialization once I know it is valid. What you posted is so far from valid there is no way it would work. I'm surprised they are returning it in that format, do they provide some kind of library for consuming their services?
If you want something even simpler, I can give you my CGIJSONObject library that will handle JSON using reflection - you just need to mirror the keys in APIs with your classes andit is good to go.
I have a webservice that returns data to my client application in JSON. I am using TouchJson to then deserialize this data into a NSDictionary. Great. The dictionary contains a key, "results" and results contains an NSArray of objects.
These objects look like this when printed to log i.e
NSLog(#"Results Contents: %#",[resultsArray objectAtIndex:0 ]);
Outputs:
Results Contents: {
creationdate = "2011-06-29 22:03:24";
id = 1;
notes = "This is a test item";
title = "Test Item";
"users_id" = 1;
}
I can't determine what type this object is. How do I get the properties and values from this object?
Thanks!
To get the content of a NSDictionary you have to supply the key for the value that you want to retrieve. I.e:
NSString *notes = [[resultsArray objectAtIndex:0] valueForKey:#"notes"];
To test if object is an instance of class a, use one of these:
[yourObject isKindOfClass:[a class]]
[yourObject isMemberOfClass:[a class]]
To get object's class name you can use one of these:
const char* className = class_getName([yourObject class]);
NSString *className = NSStringFromClass([yourObject class]);
For an NSDictionary, you can use -allKeys to return an NSArray of dictionary keys. This will also let you know how many there are (by taking the count of the array). Once you know the type, you can call
[[resultsArray objectAtIndex:0] objectForKey:keyString];
where keyString is one of #"creationdate", #"notes", etc. However, if the class is not a subclass of NSObject, then instead use:
[[resultsArray objectAtIndex:0] valueForKey:keyString];
for example, you probably need to do this for keystring equal to #"id".