title: How to open view controller after data has been loaded into model object?
body: <p>How can I check if the <code>NSData dataWithContentsOfURL</code>parsing in my secondary thread are finished? When every image is finished I want to open my view controller. Not before. Now I can open my view controller directly, and sometimes if I'm to quick my table view has no images, because they're not finished yet. Any ideas?</p>
  
  <p>The following code happens in <code>didFinishLaunchingWithOptions</code> in AppDelegate. Im using the SBJSON framework for parsing. </p>
  
  <p>(Im using the storyboard in this project so there's no code for opening the first view controller) </p>
  
  <p>Code:</p>
  
  <pre><code>NSString *filePath = [[NSBundle mainBundle] pathForResource:@"json_template" ofType:@"json"];
  NSString *contents = [NSString stringWithContentsOfFile: filePath  encoding: NSUTF8StringEncoding error: nil];
  SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
  NSMutableDictionary *json = [jsonParser objectWithString: contents];
  tabs = [[NSMutableArray alloc] init];
  jsonParser = nil;
  
  //parsing json into model objects
  for (NSString *tab in json)
  {
      Tab *tabObj = [[Tab alloc] init];
      tabObj.title = tab;
  
      NSDictionary *categoryDict = [[json valueForKey: tabObj.title] objectAtIndex: 0];
      for (NSString *key in categoryDict)
      {
  
          Category *catObj = [[Category alloc] init];
          catObj.name = key;
  
  
          NSArray *items = [categoryDict objectForKey:key];
  
          for (NSDictionary *dict in items)
          {
              Item *item = [[Item alloc] init];
              item.title = [dict objectForKey: @"title"];
              item.desc = [dict objectForKey: @"description"];
              item.url = [dict objectForKey: @"url"];
  
              if([dict objectForKey: @"image"] != [NSNull null])
              {
  
                  dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^(void)
                                 {
                                     NSURL *imgUrl = [NSURL URLWithString: [dict objectForKey: @"image"]];
                                     NSData *imageData = [NSData dataWithContentsOfURL: imgUrl];
  
                                     dispatch_async( dispatch_get_main_queue(), ^(void)
                                     {
                                         item.image = [UIImage imageWithData: imageData];
  
                                     });
                                 });
              }
              else
              {
                  UIImage *image = [UIImage imageNamed: @"standard3.png"];
                  item.image = image;
              }
  
              [catObj.items addObject: item];
  
          }
  
          [tabObj.categories addObject: catObj]; 
      }
  
      [tabs addObject: tabObj];
  
  
  }
  
  //sort array 
  [tabs sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
  
  
      Tab *r1 = (Tab*) obj1;
      Tab *r2 = (Tab*) obj2;
  
      return [r1.title caseInsensitiveCompare: r2.title];
  
  }];
  
  
  
  /***** END PARSING JSON *****/
  
  [[UINavigationBar appearance] setTitleTextAttributes: @{
                      UITextAttributeTextShadowOffset: [NSValue valueWithUIOffset:UIOffsetMake(0.0f, 0.0f)],
                      UITextAttributeFont: [UIFont fontWithName:@"GreatLakesNF" size:20.0f]
   }];
  
  UIImage *navBackgroundImage = [UIImage imageNamed:@"navbar.png"];
  [[UINavigationBar appearance] setBackgroundImage:navBackgroundImage forBarMetrics:UIBarMetricsDefault];
  UIImage *backButtonImage = [[UIImage imageNamed:@"backBtn.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
  
  UIImage *backButtonSelectedImage = [[UIImage imageNamed:@"backBtn_selected.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
  [[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
  [[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonSelectedImage forState: UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
  
  
  return YES;
  </code></pre>
  
  <p>Also, if this way of parsing is bad, please tell me!</p>