0

I have parsed json. The result of json stored in array which contain list of video ID. Now I want to parse another json which retrieve detail of video and this json will be parsed in loop videoIDArray.count times

Here is code:

- (void)viewDidLoad
{
    [super viewDidLoad];

    videoIDArray = [[NSMutableArray alloc] init];
    viewArray = [[NSMutableArray alloc] init];

    //======Json Parsing

    NSString *urlstring = [NSString stringWithFormat:@"https://myURL/youtubeList"];
    NSURL *url = [NSURL URLWithString:urlstring];

    NSURLRequest *Request = [NSURLRequest requestWithURL:url];
    conn = [[NSURLConnection alloc] initWithRequest:Request delegate:self];
    if (conn) {
        webdata = [[NSMutableData alloc] init];
    }
    //==========
}


- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    if (connection==conn) {
        [webdata setLength:0];
    }
    if (connection==conn2) {
        [webdata2 setLength:0];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    if (connection==conn) {
        [webdata appendData:data];
    }
    if (connection==conn2) {
        [webdata2 appendData:data];
    }

}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //-------conn getting list of videoID
    if (connection == conn) {
        NSString *str = [[NSString alloc] initWithBytes:[webdata bytes] length:[webdata length] encoding:NSUTF8StringEncoding];

        NSDictionary *Result = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];

        [videoIDArray addObjectsFromArray:[[[Result valueForKey:@"items"] valueForKey:@"id"] valueForKey:@"videoId"]];
        NSLog(@"Video ID %@",videoIDArray);

        //======conn2 is for getting detail of video base on videoID object
        for (int i=0; i<videoIDArray.count; i++) {
            NSString *urlstring = [NSString stringWithFormat:@"https://mydetailURL/videos/%@?v=2&alt=json",[videoIDArray objectAtIndex:i]];
            NSURL *url = [NSURL URLWithString:urlstring];

            NSURLRequest *Request = [NSURLRequest requestWithURL:url];
            conn2 = [[NSURLConnection alloc] initWithRequest:Request delegate:self];
            if (conn2) {
                webdata2 = [[NSMutableData alloc] init];
            }
        }
        //==========
    }

    if (connection==conn2) {
        [MBProgressHUD hideHUDForView:self.view animated:YES];
        [youtubeTableView reloadData];

        NSString *str = [[NSString alloc] initWithBytes:[webdata bytes] length:[webdata length] encoding:NSUTF8StringEncoding];

        NSDictionary *Result = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
        NSLog(@"ResultConn2 %@",Result);
        [viewArray addObject:[[[Result valueForKey:@"entry"] valueForKey:@"yt$statistics"] valueForKey:@"viewCount"]];
        NSLog(@"View Array %@",viewArray);
    }
}

Problem is: it is not parsing as many times as in loop, only for last one connectionDidFinishLoading method called and crashed..

Can somebody tell me how to do this?

Is there any other way to do this?

EDIT

With AFNetworking

i changed my code like:

 for (int i=0; i<videoArray.count; i++) {
      [self parseWithUrl:[videoArray objectAtIndex:i]];
   }
 -(void)parseWithUrl: (NSString *)urlstr
  {
     NSString *tstr=[urlstr stringByReplacingOccurrencesOfString:@"\"" withString:@""];
     NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://myURL/feeds/api/videos/%@?v=2&alt=json",tstr]];
     NSURLRequest *request = [NSURLRequest requestWithURL:url];
     AFJSONRequestOperation *operation =
     [AFJSONRequestOperation JSONRequestOperationWithRequest: request
                                                success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
                          //instead of NSLog i want to return result
                                                    NSDictionary *result  = (NSDictionary *)JSON;
                                                    NSLog(@"VideoResult %@",result);



                                                } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
                                                    UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Error Retrieving Weather"
                                                                                                 message:[NSString stringWithFormat:@"%@",error]
                                                                                                delegate:nil
                                                                                       cancelButtonTitle:@"OK" otherButtonTitles:nil];
                                                    [av show];
                                                }];



    [operation start];

 }

I want to write:

-(NSDictionary *)parseWithUrl: (NSString *)urlstr

Is it possible?

if Yes then suggest me where i should return result?

if i want to call another method after completing json then where to write call code

here is my code: [self getData:self.weather]; my method called number of times which i don't want.

 success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
                                                    self.weather  = (NSDictionary *)JSON;
                                                    [self getData:self.weather];
 .....

 .....
  }

2 Answers 2

2

Your issue stems from the fact that each of these NSURLConnection connections run asynchronously and therefore you're running many requests concurrently, but your routine is using a single webData2, so your requests are tripping over each other.

If you want to stay with your current design, rather than having a for loop where you initiate all of the second set of requests, you should only request the first one. And then have the connectionDidFinishLoading for the second type of request initiate the next one. (You could manage this "next" process by keeping track of some numeric index indicating which request you're processing, incrementing it each time.)

But you ask how to do these requests sequentially, one after another. Is there any reason why you cannot do them concurrently (more accurately, when first request is done, then issue the detail requests for the individual videos concurrently). In that scenario, even better than the clumsy fix I outlined in the prior paragraph, a more logical solution is an NSOperation-based implementation that:

  • Uses a separate object for each connection so the individual requests don't interfere with each other;

  • Enjoys the concurrency of NSURLConnection, but constrains the number of concurrent requests to some reasonable number ... you will yield significant performance benefits by using concurrent requests; and

  • Is cancelable in case the user dismisses the view controller while all of these requests are in progress and you want to cancel the network requests.

If you're already familiar writing NSURLConnectionDataDelegate based code, wrapping that in an NSOperation is not much worse. (See Defining a Custom Operation Object in the Concurrency Programming Guide.) We can walk you through the steps to do that, but frankly much easier is to use AFNetworking. They've done the complicated stuff for you.


In your edit to your question, you ask whether it is possible to write:

- (NSDictionary *)parseWithUrl: (NSString *)urlstr

While it's technically possible to, you never want a method on the main queue waiting synchronously for a network request. If parseWithURL cannot do what it needs to do inside the success block of the AFNetworking call (e.g. you might initiate a [self.tableView reloadData] or whatever is needed for your UI), then have parseWithURL return the dictionary in a completion handler of its own, e.g.:

- (void)parseWithURL: (NSString *)urlstr completion:(void (^)(NSDictionary *))completion
{
    ...

    AFJSONRequestOperation *operation =
    [AFJSONRequestOperation JSONRequestOperationWithRequest: request
                                                    success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

                                                        completion(JSON); // call the completion block here

                                                    } failure:...];
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @Rob my problem almost solved but please check my edit if you can help further
@ChitraKhatri Just added completion handler rendition, which it appears you found independently.
0

Finally I am done parsing synchronous multiple json parsing with help of AFNetworking

Success of json parsing call another method in AFNetworking done by: link

Here is Code:

- (void)getResponse:(void (^)(id result, NSError *error))block {
   NSString *weatherUrl = [NSString stringWithFormat:@"%@weather.php?format=json", BaseURLString];
   NSURL *url = [NSURL URLWithString:weatherUrl];
   NSURLRequest *request = [NSURLRequest requestWithURL:url];

  // 2
  AFJSONRequestOperation *operation =
   [AFJSONRequestOperation JSONRequestOperationWithRequest:request
  // 3
  success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
    //Success
               block(JSON,nil); //call block here
  }
 // 4
 failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)    {
      UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Error Retrieving     Weather"
                                                 message:[NSString stringWithFormat:@"%@",error]
                                                delegate:nil
                                       cancelButtonTitle:@"OK" otherButtonTitles:nil];
       [av show];
  }];

// 5

[operation start];

}

calling will be:

 [self getResponse:^(id result, NSError *error) {
     //use result here
 }];

Comments

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.