0

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:@"URL"]
          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?

4
  • Update your question with the exact output of NSLog(@"YouTube ID: %@", json);. BTW - It looks like the json variable should be NSDictionary, not NSArray. Commented Nov 15, 2022 at 16:45
  • As it says: So far I can return the entire JSON to the log. So, NSLog(@"YouTube ID: %@", json); returns the entire json when I am trying to return videoId only. Commented Nov 15, 2022 at 16:52
  • At least show the output of that NSLog statement from the very beginning to the videoID that you want. The point is to confirm that the actual structure you are getting matches what you are expecting. Commented Nov 15, 2022 at 16:54
  • It returns nil because the root object is a dictionary, note the { at the beginning. Commented Nov 15, 2022 at 18:15

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much this worked perfectly and a very well explained solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.