When I convert the JSON into an NSDictionary then call ObjectForKey: I get the error: -[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0xa9801d0
My code for converting:
NSError *error;
NSData *responseData = [NSData dataWithContentsOfURL:dataURL];
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
NSLog(#"%#",json);
//The exeption is hilighted here:
NSArray *objects = [[json objectForKey:#"data"] objectForKey:#"children"];
This is the file:
{
data = {
after = "<null>";
before = "<null>";
children = (
{
data = {
"approved_by" = "<null>";
author = Jonovono;
"author_flair_css_class" = "<null>";
"author_flair_text" = "<null>";
"banned_by" = "<null>";
clicked = 0;
created = 1371955129;
"created_utc" = 1371926329;
distinguished = "<null>";
domain = "self.redditdev";
downs = 1;
edited = 0;
hidden = 0;
id = 1gv8g1;
"is_self" = 1;
likes = "<null>";
"link_flair_css_class" = "<null>";
"link_flair_text" = "<null>";
media = "<null>";
"media_embed" = {
};
name = "t3_1gv8g1";
"num_comments" = 2;
"num_reports" = "<null>";
"over_18" = 0;
permalink = "/r/redditdev/comments/1gv8g1/rate_limiting_on_commenting/";
saved = 0;
score = 4;
selftext = "Can't really find anyone else having this issue. I am using this ruby library for reddit api wrapper: https://github.com/paradox460/snoo\n\nIt seems when I comment only the first one goes through, and any others fail. It does not seem to return a message, but I am guessing it's because of the message that only comment so much in so much time. How can I get around that? Or is something else causing it? Thanks.";
"selftext_html" = "<!-- SC_OFF --><div class=\"md\"><p>Can't really find anyone else having this issue. I am using this ruby library for reddit api wrapper: <a href=\"https://github.com/paradox460/snoo\">https://github.com/paradox460/snoo</a></p>\n\n<p>It seems when I comment only the first one goes through, and any others fail. It does not seem to return a message, but I am guessing it's because of the message that only comment so much in so much time. How can I get around that? Or is something else causing it? Thanks.</p>\n</div><!-- SC_ON -->";
subreddit = redditdev;
"subreddit_id" = "t5_2qizd";
thumbnail = "";
title = "Rate limiting on commenting?";
ups = 5;
url = "http://www.reddit.com/r/redditdev/comments/1gv8g1/rate_limiting_on_commenting/";
};
kind = t3;
}
);
modhash = 6dviotq5igca155758e9e858f1d863870f1b5296d9d571d45d;
};
kind = Listing;
},
{
data = {
after = "<null>";
before = "<null>";
children = (
{
data = {
"approved_by" = "<null>";
author = pipeep;
"author_flair_css_class" = "<null>";
"author_flair_text" = "<null>";
"banned_by" = "<null>";
body = "New accounts are severely rate limited on comment speed to prevent spamming. Once you accumulate some karma, that goes down rather quickly. I've found that my bot with a few thousand karma is able to post a few times a minute at peek without any problems.\n\nThe API returns an error if you post too quickly (Probably `RATELIMIT` or `SUBREDDIT_RATELIMIT`; I don't remember). You can either drop those comments or put them in a queue and retry later, hoping that your queue doesn't get too long.";
"body_html" = "<div class=\"md\"><p>New accounts are severely rate limited on comment speed to prevent spamming. Once you accumulate some karma, that goes down rather quickly. I've found that my bot with a few thousand karma is able to post a few times a minute at peek without any problems.</p>\n\n<p>The API returns an error if you post too quickly (Probably <code>RATELIMIT</code> or <code>SUBREDDIT_RATELIMIT</code>; I don't remember). You can either drop those comments or put them in a queue and retry later, hoping that your queue doesn't get too long.</p>\n</div>";
created = 1371970411;
"created_utc" = 1371941611;
distinguished = "<null>";
downs = 0;
edited = 0;
gilded = 0;
id = cao9eaf;
likes = "<null>";
"link_id" = "t3_1gv8g1";
name = "t1_cao9eaf";
"num_reports" = "<null>";
"parent_id" = "t3_1gv8g1";
replies = {
data = {
after = "<null>";
before = "<null>";
children = (
{
data = {
"approved_by" = "<null>";
author = Jonovono;
"author_flair_css_class" = "<null>";
"author_flair_text" = "<null>";
"banned_by" = "<null>";
body = "Alright, thanks. Good to know it goes down with karma. So karma is good for something.";
"body_html" = "<div class=\"md\"><p>Alright, thanks. Good to know it goes down with karma. So karma is good for something.</p>\n</div>";
created = 1372014449;
"created_utc" = 1371985649;
distinguished = "<null>";
downs = 0;
edited = 0;
gilded = 0;
id = caoivdj;
likes = "<null>";
"link_id" = "t3_1gv8g1";
name = "t1_caoivdj";
"num_reports" = "<null>";
"parent_id" = "t1_cao9eaf";
replies = "";
"score_hidden" = 0;
subreddit = redditdev;
"subreddit_id" = "t5_2qizd";
ups = 1;
};
kind = t1;
}
);
modhash = 6dviotq5igca155758e9e858f1d863870f1b5296d9d571d45d;
};
kind = Listing;
};
"score_hidden" = 0;
subreddit = redditdev;
"subreddit_id" = "t5_2qizd";
ups = 1;
};
kind = t1;
}
);
modhash = 6dviotq5igca155758e9e858f1d863870f1b5296d9d571d45d;
};
kind = Listing;
}
)
I need to be able to get any object from the JSON but I do not know why this exception is being thrown.
Do you see that lonely ) right at the end of the JSON output you've provided. If you look at the actual log from Xcode you're likely to see that there is a matching ( which you've forgotten to copy and paste into your question.
What you actually have is JSON object that is an array not a dictionary, so when you are trying to get values for keys, the compiler is telling you that the array doesn't respond to that message.
That should help you unpack your JSON object, you need to iterate through an array of dictionaries extracting the values you need.
I will complete #Abizem answer by adding a short piece of code because I see that you are a beginner (I don't have any problem with that) and I know that when you start programming or a new language, code snippets are really useful (doesn't meter that google is full of JSON parsing tutorials and SO is full of posts that are having your problem unrecognized selector when parsing.)
So whenever you have a JSON that starts with ( it means that the JSON is an array, if the JSON starts with a { then the JSON is a dictionary.
In order to get objects from a JSON array you will have to iterate over it. The objects contained by the JSON can be dictionaries or arrays.
So if you have only dictionaries into your array you should use:
for(NSDictionary *contentDictionary in yourJSONObject) {
//do stuffs with your dictionary
}
If you have only arrays into your JSON you should use:
for(NSArray *contentArray in yourJSONObject) {
//do stuffs with your dictionary
}
If you have both arrays and dictionaries in your JSON you should use:
for(id unknownType in yourJSONObject) {
if([unknownType isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict = (NSDictionary*)unknownType;
}
else if ([unknownType isKindOfClass:[NSArray class]]{
NSArray *array = (NSArray *)unknownType;
}
}
If your JSON is a dictionary then you can use the NSDictionary methods to get the proper values:
[dictJSON objectForKey:#"myKey"];
The JSON is an array not a dictionary. Get the first element from the array before you access it as a dictionary.
Your object json is an NSArray which you're trying to access like a NSDictionary (objectForKey:)
Related
I have an NSDictionary, named "thisList", and I need to get the value of its key "list_collection".
Xcode indicates that the value is a "NSSingleEntryDictionary".
The value itself contains an array with yet another dictionary.
Please take a look at the screenshot:
Now, no matter what I try (objectforKey/valueforKey) or whatever type of object I initialize (NSArray/NsMutableArray/NSDictionary/NSMutableDictionary) I end up with a nil value.
Apparently, I miss some essential knowledge on how to handle this.
My question: how should I initialize an object with the value of the key "list_collection".
Here is a (partial) dump of the json:
Printing description of thisList:
{
archived = 0;
"chapter_part" = "";
"chapter_title" = "";
comment = "";
"cover_id" = "<null>";
"created_at" = "2017-01-06T12:59:04.000+01:00";
"date_created" = "06 January 2017";
deleted = 0;
id = 141384502;
isMyList = 1;
keywords = (
);
"list_collection" = {
lists = (
{
"speech_locale" = EN;
subject = engels;
words = (
{
word = attitude;
},
The to me most logical approach would be:
NSDictionary * myDic = [thisList objectForKey:#"list_collection"];
Note: I didn't explicitly initialize 'myDic' here.
To put things in context, here is my code:
NSString * hlists = [json objectForKey:#"lists"];
NSData* data = [hlists dataUsingEncoding:NSUTF8StringEncoding];
NSArray *wrtsLists = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonParsingError];
Lists = [[NSMutableArray alloc]init];
for (NSDictionary *thisList in wrtsLists){
WordList* theList = [[WordList alloc]init];
theList.title = [thisList valueForKey:#"title"];
[Lists addObject:theList];
NSDictionary *myDic = thisList[#"list_collection"];
>>>>this is where I put a breakpoint. myDic is nil here
}
Thanks for your insights.
You can simply get "list_collection" array from "thisList" using by this code
NSDictionary *myDic = thisList[#"list_collection"];
In the end, I figured out, that it was an Xcode problem.
The Debug area just didn't correctly display the values of my objects.
I restarted Xcode, and things started to work as expected.
I lost several hours of my life on this. But I learned a lot, thanks to your good advises.
Try this hope it helps You
NSDictionary *myDic = [thelist valueForKey:"list_collection"];
I have recently used the following code to extract the ID of a location from a Foursquare API call with:
NSDictionary* foursquareJson = [NSJSONSerialization JSONObjectWithData:secureData options:kNilOptions error:&error];
NSDictionary *venuesDict = foursquareJson[#"response"];
NSArray *venuesArray = venuesDict[#"venues"];
NSDictionary *venuesDict2 = venuesArray[0];
NSArray *categoriesDict = venuesDict2[#"categories"];
NSDictionary *idDict = categoriesDict[0];
NSLog(#"ID is %#",idDict[#"id"]);
with original foursquareJson being:
2015-03-30 17:16:40.700 Voyagic[2833:718563] {
meta = {
code = 200;
};
response = {
venues = (
{
categories = (
{
icon = {
prefix = "https://ss3.4sqi.net/img/categories_v2/building/conventioncenter_";
suffix = ".png";
};
id = 4bf58dd8d48988d1ff931735;
name = "Convention Center";
pluralName = "Convention Centers";
primary = 1;
shortName = "Convention Center";
}
);
contact = {
formattedPhone = "+44 20 7222 5000";
phone = "+442072225000";
};
hereNow = {
count = 0;
groups = (
);
summary = "Nobody here";
};
id = 4b6599d4f964a520f8f52ae3;
location = {
address = "Broad Sanctuary";
cc = GB;
city = London;
country = "United Kingdom";
distance = 2167;
formattedAddress = (
"Broad Sanctuary",
London,
"Greater London",
"SW1P 3EE",
"United Kingdom"
);
lat = "51.49997800145596";
lng = "-0.1289014132864838";
postalCode = "SW1P 3EE";
state = "Greater London";
};
name = "Queen Elizabeth II Conference Centre";
referralId = "v-1427732200";
specials = {
count = 0;
items = (
);
};
stats = {
checkinsCount = 3657;
tipCount = 15;
usersCount = 2407;
};
verified = 0;
}
);
};
}
but there surely must be a better way of accessing the ID which I don't know about (instead of creating 4 dictionaries and 2 array, which seems somewhat excessive :/ ). Any help would be greatly appreciated :)
Ultimately, the data will need to be accessed through the lists of dictionaries and arrays somehow, it just depends on where you want that to happen. You could use or make a parser for the JSON but that will ultimately still need to map the JSON data similarly to what you are doing. A simple and shorter way of accessing the data would be to not create a new variable in every iteration. Although it really is not much different:
NSDictionary *foursquareJson = [NSJSONSerialization JSONObjectWithData:secureData options:kNilOptions error:&error];
NSDictionary *objectId = foursquareJson[#"response"][#"venues"][0][#"categories"][0][#"id"];
NSLog(#"ID is %#",objectId);
Because of the dialogue in the comments of this answer I figured I should probably include a bit more information about your concern with creating "4 dictionaries and 2 arrays". When you use the JSON Serializer to create native objects from the JSON (first line above) you are creating all of the arrays and dictionaries needed to fully represent and store the entire JSON. The difference in code samples between what you originally posted and what I provided is really not a significantly different. If you are concerned with creating too many dictionaries or arrays you should attempt to filter out the JSON prior to deserializing it into native objects.
I have this NSDictionary that i received from an api call:
{
items = (
{
accessInfo = {
accessViewStatus = SAMPLE;
country = US;
embeddable = 1;
epub = {
isAvailable = 0;
};
pdf = {
isAvailable = 0;
};
publicDomain = 0;
quoteSharingAllowed = 0;
textToSpeechPermission = ALLOWED;
viewability = PARTIAL;
webReaderLink = "http://books.google.com/books/reader?id=LdB2_WzYpKgC&hl=&printsec=frontcover&output=reader&source=gbs_api";
};
etag = 1xxAlevFUSc;
id = "LdB2_WzYpKgC";
kind = "books#volume";
saleInfo = {
country = US;
isEbook = 0;
saleability = "NOT_FOR_SALE";
};
searchInfo = {
textSnippet = "The saga of their daily exploits won cartoonist Bill Watterson the coveted Reuben Award for "Outstanding Cartoonist of the Year." Something Under the Bed Is Drooling is a jewel.";
};
selfLink = "https://www.googleapis.com/books/v1/volumes/LdB2_WzYpKgC";
volumeInfo = {
authors = (
"Bill Watterson"
);
averageRating = "4.5";
canonicalVolumeLink = "http://books.google.com/books/about/Something_Under_the_Bed_Is_Drooling.html?hl=&id=LdB2_WzYpKgC";
categories = (
Humor
);
contentVersion = "0.0.1.0.preview.1";
description = "\"Be good to yourself: Buy a copy of this Calvin and Hobbes cartoon book. If you don't laugh out loud at every third strip, check your pulse. You may be dead.\" --Phil Musick, Pittsburgh Press Calvin is a rambunctious six-year-old whose manic antics threaten world peace. Hobbes is his stuffed tiger who comes alive when adults aren\"t around. The saga of their daily exploits won cartoonist Bill Watterson the coveted Reuben Award for \"Outstanding Cartoonist of the Year.\" Something Under the Bed Is Drooling is a jewel.";
imageLinks = {
smallThumbnail = "http://bks8.books.google.com/books?id=LdB2_WzYpKgC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api";
thumbnail = "http://bks8.books.google.com/books?id=LdB2_WzYpKgC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api";
};
industryIdentifiers = (
{
identifier = 0836218256;
type = "ISBN_10";
},
{
identifier = 9780836218251;
type = "ISBN_13";
}
);
infoLink = "http://books.google.com/books?id=LdB2_WzYpKgC&dq=isbn:0836218256&hl=&source=gbs_api";
language = en;
pageCount = 127;
previewLink = "http://books.google.com/books?id=LdB2_WzYpKgC&printsec=frontcover&dq=isbn:0836218256&hl=&cd=1&source=gbs_api";
printType = BOOK;
publishedDate = "1988-01-01";
publisher = "Andrews McMeel Publishing";
ratingsCount = 18;
readingModes = {
image = 1;
text = 0;
};
title = "Something Under the Bed Is Drooling";
};
}
);
kind = "books#volumes";
totalItems = 1;
}
What I want to do is create an object from the items in this dictionary. This method needs to work generically for all books without crashing. Even if they are missing some of the attributes. The attributes I need to extract are:
-authors last name (Need for every author listed if there is more than one)
-authors first name (Need for every author listed if there is more than one)
-title
-description
-smallThumbnail
-thumbnail
-isbn_10 identifier
-category
From these I am going to create a "book" object. i will also create an NSSet of Authors, and each Author has a lastName and firstName
How do I go about doing this?
You should be able to safely use NSDictionary's -valueForKeyPath: to retrieve each value from an item dict:
NSArray *names = [itemDict valueForKeyPath:#"volumeInfo.authors"];
NSString *title = [itemDict valueForKeyPath:#"volumeInfo.title"];
...
I got this json response
{
"generated_in" = "0.0283";
stat = ok;
videos = {
"on_this_page" = 3;
page = 1;
perpage = 50;
total = 3;
video = (
{
"embed_privacy" = anywhere;
id = 73198189;
"is_hd" = 1;
"is_watchlater" = 0;
license = 0;
"modified_date" = "2013-08-27 01:29:16";
owner = 20303618;
privacy = anybody;
title = Untitled;
"upload_date" = "2013-08-27 00:57:36";
},
{
"embed_privacy" = anywhere;
id = 73197989;
"is_hd" = 0;
"is_watchlater" = 0;
license = 0;
"modified_date" = "2013-08-27 01:24:17";
owner = 20303618;
privacy = anybody;
title = sample2;
"upload_date" = "2013-08-27 00:52:40";
},
{
"embed_privacy" = anywhere;
id = 72961770;
"is_hd" = 0;
"is_watchlater" = 0;
license = 0;
"modified_date" = "2013-08-23 05:57:48";
owner = 20303618;
privacy = anybody;
title = sample;
"upload_date" = "2013-08-23 05:25:44";
}
);
};
}
when i am trying to parse it for the video id.
The technique i used is
i converted that json into NSDictionary jsondata and
NSString *videoid = [[[jsondata objectForKey:#"videos"]valueForKey:#"video"]valueForKey:#"id"];
NSLog(#"video string is %#",videoid);
the result is:
(
73198189,
73197989,
72961770
)
but i am not able to access the normal string functions on that string to retrieve the id's.
it is saying an error unrecognized selector was sent.
Is there a better way to parse that string, i tried google but every post says the same approach.
You not getting a string but an array of strings, the JSON response holds mutiple videos. The code you used will retrieve all the id of all the videos.
You can loop thru the found videos like:
NSArray *videoIdArray = [jsondata valueForKeyPath:#"videos.video.id"];
for(NSString *videoId in videoIdArray) {
NSLog(#"video string is %#",videoId);
}
I'm really stuck right now while using BZForursquare to get nearby Venues into a UITableView.
BZFoursquare: https://github.com/baztokyo/foursquare-ios-api
I get my Requestresult inside the requestDidFinishLoading Delegate Method. In this Method the request Object contains several NSDictionaries and one Dictionary is in request.response. This response Dictionary contains one entry with key="venues" and as Value a JSON Object. When I put this value Object into a dictionary the type seems not to be a Dictionary but a NSCFArray:
#pragma mark BZFoursquareRequestDelegate
- (void)requestDidFinishLoading:(BZFoursquareRequest *)request {
self.meta = request.meta;
self.notifications = request.notifications;
self.response = [request.response objectForKey:#"venues"];
self.request = nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSLog(#"%#",[self.response objectForKey:#"name"]);
}
I assume this because the NSLog Line gives me the following error:
-[__NSCFArray objectForKey:]: unrecognized selector sent to instance 0x1e5c90f0
Now I'm totaly confused and tried some failed attempts to get this JSON from whatever kind od Datatype it is into a NSDictionary. One attempt was to put the value Object into an NSString and use
[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:&error];
to get it into a Dictionary but that also failed because it still remains a NSCFArray. Can someone please tell me how I get content of
[request.response objectForKey:#"venues"]
into a NSDictionary so that I can populate my UITabelview with this content?
EDIT:
Here is whats in the value part from the Dictionary request.response:
(
{
categories = (
{
icon = {
name = ".png";
prefix = "https://foursquare.com/img/categories/food/default_";
sizes = (
32,
44,
64,
88,
256
);
};
id = 4bf58dd8d48988d10b941735;
name = "Falafel Restaurant";
pluralName = "Falafel Restaurants";
primary = 1;
shortName = Falafel;
}
);
contact = {
};
hereNow = {
count = 0;
groups = (
);
};
id = 4df3489dfa76abc3d86c4585;
likes = {
count = 0;
groups = (
);
};
location = {
cc = DE;
city = "Vinn";
country = Germany;
distance = 92;
lat = "51.44985";
lng = "16.648693";
state = "Nordrhein-Westfalen";
};
name = "Yildiz D\U00f6ner";
specials = (
);
stats = {
checkinsCount = 3;
tipCount = 0;
usersCount = 2;
};
verified = 0;
}
And this seems to be from Type of NSCFArray. And how can I create from this another Dictionary so that I can access the JSON Values by key? Sorry if I'm really slow today...
You ask for "venues" which I assume is an array of such. So after deserializing the json, log the return object to see what you get. It's almost for sure an array of dictionaries.