In my app i'm using a users feeds to retrieve al the post done by my app. I simply retrieve al the posts, and the compare on every post the id number of the app.
This work ok. But i've found a bug in this method. Since the application node isn't always consistent. Normally when there is a post which is not done by an app, the entry in the dictionary just says (null), there isn't any data. This doesn't give any problems.
But there is an app which has other data in the this application node. This one has data in this node which specifically says (note the difference between () and <> ). But I can't seem any way to check if the dictionary with that post has in it. i've tried the following:
NSDictionary *resultPost1 =[resultPost objectForKey:#"application"];
NSLog(#"result%#", [resultPost objectForKey:#"application"]);
if ([resultPost1 count] != 0) {
This one gives a sigabrt, with the following nslog before the sigabrt:
result(null)
result{
id = 1957711133323244365557378;
name = "app";
}
result< null > (added space for visibility)
I've also tried isEqualtoString:#"< null>" Also without success.
It looks like sometimes, their is an dictionary in the application node, and sometimes a string .
Anyone has clue??? Thanks!!!
You will have to do some checking as you don't have a guarantee as to what sort of object is returned from the dictionary.
NSDictionary *resultPost1 = [resultPost objectForKey:#"application"];
if ([[resultPost1 class] isKindOfClass:[NSDictionary class]) {
//Treat as a dictionary
}
else if ([[resultPost1 class] isKindOfClass:[NSString class]) {
//Treat as a string
}
else if ([resultPost1 isEqual:[NSNull null] || !resultPost) {
//Treat as Null, note the json library Facebook uses might set
//a json NULL into a NSNull object instead of nil
}
Related
I recently try to change the Json library in my applicaiton from SBJson to the NSJSONSerialization.
When I do this job, I find there are some key value that I can not get out.
Here is an example of the NSDictionary I get after NSJSONSerialization:
{
id = 4028;
"novel_author" = "XYZ";
"novel_pub" = "ABC";
"novel_title" = "DATE LIVE";
updatedate = "2013-01-13 22:31:13";
"vol_click" = 7563;
}
The original Json data string is:
{
"id":"4028",
"vol_click":"7563",
"updatedate":"2013-01-13 22:31:13",
"novel_author":"XYZ",
"novel_pub":"ABC",
"novel_title":"DATE LIVE"
}
I can not get the value of the key "id" out.
[NSDictionary objectForKey#"id"] is useless.
Is there anyone have idea how to get the value out?
As you can tell by the output of what looks like NSLog("%#", dict);, the JSON deserialization process works fine.
The dictionary contains a key called "id", so [dict objectForKey:#"id"] should also work fine.
I can only conclude that this isn't the actual cause of the trouble you're having.
Either of these should work:
[yourDictName valueForKey:#"id"]
[yourDictName objectForKey:#"id"]
If you can see the value using NSLog to display the dictionary, then it is there. Beyond that, make sure your object is not getting nil'd or released or freed.
I'm trying to get some app info using Apple API, that gives me an JSON file containing many objects.
I tried to determine the type of the app (Universal/iPhone only/iPad only) like this
if(([[appDetails objectForKey:#"screenshotUrls"] count]>0) && ([[appDetails objectForKey:#"ipadScreenshotUrls"] count]>0))
{
cell.appDeviceLabel.text = #"Universal";
cell.appDeviceLabel.backgroundColor = [UIColor colorWithRed:0.012 green:0.467 blue:0.784 alpha:1];
}
else if(([[appDetails objectForKey:#"screenshotUrls"] count]==0) && ([[appDetails objectForKey:#"ipadScreenshotUrls"] count]>0))
{
cell.appDeviceLabel.text = #"iPad";
cell.appDeviceLabel.backgroundColor = [UIColor colorWithRed:0.941 green:0.58 blue:0.016 alpha:1];
}
else if(([[appDetails objectForKey:#"screenshotUrls"] count]>0) && ([[appDetails objectForKey:#"ipadScreenshotUrls"] count]==0))
{
cell.appDeviceLabel.text = #"iPhone";
cell.appDeviceLabel.backgroundColor = [UIColor colorWithRed:0.016 green:0.459 blue:0.129 alpha:1];
}
Note : screenshotUrls is an array containing the images for the iphone version
ipadScreenshotUrls is the one for iPad photos.
I used the code above in my app and Apple accept it, but I get crash reports showing a problem at these lines.
May be because I'm testing the count of an array that is not found? because if the app is iphone only for exemple, the array for iPad images won't exist. Any idea how can I solve this ?
Thanks.
Does the JSON contains the value null for some key?
If yes, this value is converted to NSNull in Obj-C and any method passed to this objects results in a crash. (NSNull is different from nil in this respect.)
I usually encounter crashes with JSON in Obj-C for this reason very frequently. You should put a check in place before using any value.
if (value == (typecast)[NSNull null]) {
// use the value
}
Note that type casting is done only to avoid compiler warning.
I have an NSDictionary that looks kind of like this:
list
{{
-> id
-> name
-> color
},
{
-> id
-> name
-> color
}}
which works great when I loop through it! But unfortunately, sometimes, the structure looks like this:
list {
-> id
-> name
-> color
}
Where there's only one result returned. So I need to know if there's one or if there's more than one result returned.
I tried checking for the number of results by seeing if the ID key exists in "list" but unfortunately when I do valueForKey I get back something like this for multiple results: (429, 24) and just 429 if there's only one result.
But I can't do a count on the 429 value obviously.
Here's one of the things I was trying to do, which works great for multiple results, but not if there's one.
NSInteger numResults = [[list valueForKeyPath:#"id.#count"] intValue];
Any idea how to find out if it's an set of results or just a single result? I don't have any control over the data as it comes from a JSON object via a web service.
I also tried using [list mutableArrayValueForKey:#"id"]; and that seems to still only return an array if there's more than one result. I assumed I'd get back an array with one element if there was only one element...but apparently not?
You can check which kind of object you are dealing with using isKindOfClass:
NSInteger numResults = 1;
if ([list isKindOfClass:[NSArray class]]) {
numResults = [list count];
}
If I understand correctly, one result will actually give you an NSDictionary, but multiple results will give you an NSArray of NSDictionaries?
Assuming that is the case, you could check the type of object you have like this:
if ([list isKindOfClass:[NSDictionary class]]) {
// Must be single result
}
else {
// Multiple results case
}
Otherwise, if I've misunderstood, perhaps you could clarify.
Is there a way to directly access an inner-array of an an outer array in Objective-C? For example, a call to an external data source returns the following object:
{
bio = "this is the profile.bio data";
"first_name" = John;
"last_name" = Doe;
location = {
name = "Any Town, Any State";
};
metadata = {
pictures = {
picture = "https://picture.mysite.com/picture.jpeg";
}
}
}
I want to be able to access, for example, the location.name or the metadata.pictures.picture data. Dot notation, however, does not seem to work. For example:
_gfbLocation = [result objectForKey:#"location.name"];
_gfbPicture = [result objectForKey:#"metadata.pictures.picture"];
The only way I have been able to access this data is by first setting the contents of the inner arrays to objects. Thoughts?
For nested keys like that you can use a keyPath. A keyPath is just a series of keys joined with dots. You can use them to retrieve nested values from objects that support Key-Value Coding - including NSDictionary objects like yours. So in your case this should work:
[result valueForKeyPath:#"location.name"];
For more detail on Key-Value Coding, see Apple's Key-Value Coding Programming Guide.
See also this related StackOverflow question.
Using the correct answer by Simon Whitaker, I was able to build a hierarchy of constants by embedding a Dictionary in a Dictionary in a Dictionary. Below is example source code, modified from my real source code.
This is a real-world problem-solution. In my particular case, the goal was organizing the strings that identify products accessed via StoreKit for In-App Purchase in Apple's App Store for iOS. Imagine our app presents content from a pair of books, one on cats, the other dogs. Furthermore, our app sells an abridged version of the content as well as unabridged. Upgrading from the abridged to the unabridged means a third product, "upgrade". Each pair of books might be translated, in this case English and Italian.
Looking at the strings I'm trying to track, you might think "Why doesn't that guy just use the strings themselves rather than going through this KVC nonsense?". Well, notice the 2nd string, English > Cats > Unabridged. The string ends with an appended underscore. That's because when I used iTunesConnect to create the In-App Purchase products, I accidentally created that item as "Consumable" instead of "Non-Consumable". Apple does not allow changing the ID, even if you delete said product. So the original string could not be used; alternatively, I appended the underscore as a workaround. So the point is, these strings are arbitrary and messy.
Another similar need for this approach would by if these string values might occasionally change at compile-time, so you don't want to be copy-pasting into more than one place in your source-code. A hierarchy of constants, in other words.
Inside Xcode, I want a better way of referring to these product identifiers.
// Using new literals syntax in later versions of Xcode 4 (& 5) to declare and populate a dictionary nested in a dictionary also in a dictionary.
NSDictionary *productIdentifiersHierarchy = #{
#"en" : #{
#"cats" : #{
#"abridged" : #"com.example.My_App.cats_abridged_en",
#"unabridged" : #"com.example.My_App.cats_unabridged_en_",
#"upgrade" : #"com.example.My_App.cats_upgrade_en"
},
#"dogs" : #{
#"abridged" : #"com.example.My_App.dogs_abridged_en",
#"unabridged" : #"com.example.My_App.dogs_unabridged_en",
#"upgrade" : #"com.example.My_App.dogs_upgrade_en"
}
},
#"it" : #{
#"cats" : #{
#"abridged" : #"com.example.My_App.cats_abridged_it",
#"unabridged" : #"com.example.My_App.cats_unabridged_it",
#"upgrade" : #"com.example.My_App.cats_upgrade_it"
},
#"dogs" : #{
#"abridged" : #"com.example.My_App.dogs_abridged_it",
#"unabridged" : #"com.example.My_App.dogs_unabridged_it",
#"upgrade" : #"com.example.My_App.dogs_upgrade_it"
}
}
};
Here's how to access these triple-nested dictionaries.
// Use KVC (Key-Value Coding) as a convenient way to access the nested dictionary structure.
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"en.cats.abridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"en.cats.unabridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"en.cats.upgrade"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"en.dogs.abridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"en.dogs.unabridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"en.dogs.upgrade"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"it.cats.abridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"it.cats.unabridged"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"it.cats.upgrade"],
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"it.dogs.abridged"] );
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"it.dogs.unabridged"] );
NSLog( [productIdentifiersHierarchy valueForKeyPath:#"it.dogs.upgrade"] );
gfbPicture = [[[result objectForKey:#"metadata"] objectForKey:#"pictures"] objectForKey:#"picture"];
I'm having a problem with relationships between to entities in Core Data. I'm parsing some JSON and adding the entities:
if ([hourSets isKindOfClass:[NSArray class]]) { // check to see that we have got some hours back
for (NSDictionary *hourSet in hourSets) {
Hourset *thisHourSet = (Hourset *)[NSEntityDescription
insertNewObjectForEntityForName:#"Hourset"
inManagedObjectContext:managedObjectContext];
[thisHourSet setStartDate:[hourSet objectForKey:#"start_date"]];
[thisHourSet setEndDate:[hourSet objectForKey:#"end_date"]];
[record addHoursetsObject:thisHourSet];
}
}
...and then later trying to grab them again:
NSSet *hourSets = [self.listing valueForKeyPath:#"hoursets.hourset"];
NSLog(#"There are %# hourSets", [hourSets count]);
I'm getting Program received signal: “EXC_BAD_ACCESS”. when trying to access that hourSets NSSet in any way, including just counting the items in it.
Any suggestions? Pretty stumped. Thanks!
I am inferring your entity graph here but:
[self.listing valueForKeyPath:#"hoursets.hourset"]
... translates to a keypath of listing.hoursets.hourset which does not appear to return a set. Both the first and last elements are singular and therefore by convention not sets.
I would suggest logging the class of the return to confirm what, if anything, you're getting back.
Update:
(Forehead slap) The problem is actually the log statement itself. It should be:
NSLog(#"There are %d hourSets", [hourSets count]);
... because count returns an NSUInteger.