I am trying to return videoId from the JSON file at a URL
{
"kind": "youtube#searchListResponse",
"etag": "imd66saJvwX2R_yqJNpiIg-yJF8",
"regionCode": "US",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
},
"items": [
{
"kind": "youtube#searchResult",
"etag": "BeIXYopOmOl2niJ3NJzUbdlqSA4",
"id": {
"kind": "youtube#video",
"videoId": "1q7NUPF6j8c"
},
(Correct return in the example is 1q7NUPF6j8c). I would then like to load the video id in a
[self.playerView loadWithVideoId:@"the JSON video ID"];
So far I can return the entire JSON to the log with:
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:@"https://i-doser.com/radio/livestream.json"]
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
NSArray* json = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
NSLog(@"YouTube ID: %@", json);
//NSArray *videoid = [json valueForKeyPath:@"items.0.id.videoId"];
//NSLog(@"VideoID: %@", videoid);
}] resume];
This returns to NSLOG:
**App [6094:1793786] YouTube ID: {
etag = "imd66saJvwX2R_yqJNpiIg-yJF8";
items = (
{
etag = BeIXYopOmOl2niJ3NJzUbdlqSA4;
id = {
kind = "youtube#video";
videoId = 1q7NUPF6j8c;
};
kind = "youtube#searchResult";**
(and the rest of the json).
I have tried this as a shot in the dark.
//NSArray *videoid = [json valueForKeyPath:@"items.0.id.videoId"];
//NSLog(@"VideoID: %@", videoid);
But that returns null.
How can I return just the videoID
and pass it to the self.playerView loadWithVideoId
?
CodePudding user response:
I think you're on the right track. I've added to your sample json below just as an example where there are multiple items in the "items"
array for illustration purposes:
{
"kind": "youtube#searchListResponse",
"etag": "imd66saJvwX2R_yqJNpiIg-yJF8",
"regionCode": "US",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 1
},
"items": [
{
"kind": "youtube#searchResult",
"etag": "BeIXYopOmOl2niJ3NJzUbdlqSA4",
"id": {
"kind": "youtube#video",
"videoId": "1q7NUPF6j8c"
},
},
{
"kind": "youtube#searchResult",
"etag": "secondETag",
"id": {
"kind": "youtube#video",
"videoId": "secondVideoId"
},
}
]
}
One line of your code which I noticed first is that you're expecting an NSArray when parsing the json object:
NSArray* json = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
You should be expecting an NSDictionary as the top level object according to your sample input:
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
Now onto the valueForKeyPath
If you were to use something like this:
[jsonDict valueForKeyPath:@"items.id.videoId"]
You would get an NSArray of all the video ids:
(
1q7NUPF6j8c,
secondVideoId
)
And then you want the first one of those so you can use @firstObject
as the "collection operator" to get the first object. So the full key path would be:
NSString *videoId = [jsonDict valueForKeyPath:@"items.id.videoId.@firstObject"];
Which results in: 1q7NUPF6j8c
There's some additional documentation in the Key Value Coding Programming guide for using collection operators here: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/CollectionOperators.html#//apple_ref/doc/uid/20002176-BAJEAIEE
While it's not explicitly spelled out (or documented) on that page that you can use @firstObject
, here are some portions of it which hint at the solution from the first couple of paragraphs:
A collection operator is one of a small list of keywords preceded by an at sign (@) that specifies an operation that the getter should perform to manipulate the data in some way before returning it.
When a key path contains a collection operator, any portion of the key path preceding the operator, known as the left key path, indicates the collection on which to operate relative to the receiver of the message.