title: NSFetchedResultsController & UITableViewController not communicating
body: <p>I have some "details" saved into my Core Data, and I'm trying to call it out from an <code>NSFetchedResultsController</code> into my <code>tableView</code>. For whatever reason, the <code>tableView</code> isn't populating once the block is finished running. </p>
  
  <p>I have been searching and asking everywhere I can to try and figure out this whole Core Data debacle. Hopefully, someone on here is kind enough to help me out!</p>
  
  <p>HomeViewController.m</p>
  
  <pre><code>- (void)viewDidLoad
  {
      [super viewDidLoad];
  
      self.navigationItem.title = @"Home";
      self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:0 green:0.7 blue:2.3 alpha:1];
  
      self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCompose target:self action:@selector(addShindy:)];
  
      self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"light_alu.png"]];
      self.tableView.opaque = NO;
      self.tableView.backgroundView = nil;
  
      UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
      [refreshControl addTarget:self action:@selector(refresh:)
               forControlEvents:UIControlEventValueChanged];
      self.refreshControl = refreshControl;
  
      [self setShindyDatabase:self.shindyDatabase];
  
  }
  
  - (void)viewWillAppear:(BOOL)animated
  {
      [super viewWillAppear:animated];
  
      if (!self.shindyDatabase) {
          NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
          self.shindyDatabase = [[UIManagedDocument alloc] initWithFileURL:url];
      }
  }
  
  - (void)refresh:(UIRefreshControl *)sender
  {
      [self useDocument];
      [sender endRefreshing];
  }
  
  - (void)addShindy:(UIBarButtonItem *)sender
  {
      AddShindyViewController *addShindyViewController = [[AddShindyViewController alloc] initWithNibName:@"AddShindyViewController" bundle:nil];
      UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addShindyViewController];
      [self presentViewController:navController animated:YES completion:nil];
  }
  
  - (void)didReceiveMemoryWarning
  {
      [super didReceiveMemoryWarning];
      // Dispose of any resources that can be recreated.
  }
  
  #pragma Core Date Stack
  
  - (void)fetchShindyDataIntoDocument:(UIManagedDocument *)document
  {
      dispatch_queue_t fetchIntoDocument = dispatch_queue_create("Fetch Into Document", nil);
      dispatch_async(fetchIntoDocument, ^{
          NSArray *shindys = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
          for (NSDictionary *shindyInfo in shindys) {
              [Shindy shindyWithShindyDBInfo:shindyInfo inManagedObjectContext:document.managedObjectContext];
          }
          [document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
      });
  }
  
  - (void)setShindyDatabase:(UIManagedDocument *)shindyDatabase
  {
      if (_shindyDatabase != shindyDatabase) {
          _shindyDatabase = shindyDatabase;
          [self useDocument];
      }
  }
  
  - (void)useDocument
  {
      NSError *error = nil;
  
      if (![[NSFileManager defaultManager] fileExistsAtPath:[self.shindyDatabase.fileURL path]]) {
          NSLog(@"Create document");
          [self.shindyDatabase saveToURL:self.shindyDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
              [self setupFetchedResultsController];
              [self fetchShindyDataIntoDocument:self.shindyDatabase];
  
              if (!success) {
                  NSLog(@"error for creation of document: %@", [error localizedDescription]);
              }
          }];
      } else if (self.shindyDatabase.documentState == UIDocumentStateClosed) {
          NSLog(@"Closed document");
          [self.shindyDatabase.managedObjectContext.parentContext performBlock:^{
              [self setupFetchedResultsController];
          }];
      } else if (self.shindyDatabase.documentState == UIDocumentStateNormal) {
          NSLog(@"Normal Document");
          [self setupFetchedResultsController];
      }
  
      if (error) {
          NSLog(@"Error in useDocument: %@", [error localizedDescription]);
      }
  }
  
  - (void)setupFetchedResultsController
  {
      NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Shindy"];
      NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"details" ascending:YES];
      request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
      // request.predicate = [NSPredicate predicateWithFormat:@"details = %@", [self.shindyDatabase valueForKey:@"details"]];
      self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                              managedObjectContext:self.shindyDatabase.managedObjectContext
                                                                                sectionNameKeyPath:nil
                                                                                      cacheName:nil];
  }
  
  #pragma mark - Table view data source
  
  - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
  {
      return 75;
  }
  
  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  {
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
  
      if (cell == nil) {
          cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
      }
  
      Shindy *shindy = [self.fetchedResultsController objectAtIndexPath:indexPath];
      NSLog(@"%@", shindy.details);
      cell.textLabel.text = shindy.details;
  </code></pre>
  
  <p>Shindy+CreateDB.m</p>
  
  <pre><code>+ (Shindy *)shindyWithShindyDBInfo:(NSDictionary *)shindyInfo
              inManagedObjectContext:(NSManagedObjectContext *)context
  {
      Shindy *shindy = nil;
  
      NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Shindy"];
  
      // NSSortDescriptor *dateAndTimeSort = [NSSortDescriptor sortDescriptorWithKey:@"dateAndTime" ascending:YES];
      NSSortDescriptor *detailsSort = [NSSortDescriptor sortDescriptorWithKey:@"details" ascending:YES];
      // NSSortDescriptor *locationSort = [NSSortDescriptor sortDescriptorWithKey:@"location" ascending:YES];
      // NSSortDescriptor *nameSort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
      // NSSortDescriptor *photoSort = [NSSortDescriptor sortDescriptorWithKey:@"photo" ascending:YES];
      // NSSortDescriptor *timePostedSort = [NSSortDescriptor sortDescriptorWithKey:@"timePosted" ascending:YES];
      // title
      request.sortDescriptors = [NSArray arrayWithObject:detailsSort];
      // request.sortDescriptors = [NSArray arrayWithObjects:dateAndTimeSort, detailsSort, locationSort, nameSort, photoSort, timePostedSort, nil];
  
      NSError *error = nil;
      NSArray *matches = [context executeFetchRequest:request error:&amp;error];
  
      if (error) {
          NSLog(@"document failed in file: %@", [error localizedDescription]);
      }
  
      if (!matches || ([matches count] &gt; 1)) {
          NSError *error = nil;
          NSLog(@"error in DBInfo: %@", [error localizedDescription]);
      } else if ([matches count] == 0) {
          shindy = [NSEntityDescription insertNewObjectForEntityForName:@"Shindy" inManagedObjectContext:context];
  
          // shindy.dateAndTime = [shindyInfo objectForKey:@"dateAndTime"];
          shindy.details = [shindyInfo objectForKey:@"details"];
          // shindy.location = [shindyInfo objectForKey:@"location"];
          // shindy.name = [shindyInfo objectForKey:@"name"];
          // shindy.photo = [shindyInfo objectForKey:@"photo"];
          // shindy.timePosted = [shindyInfo objectForKey:@"timePosted"];
          // title
          // Guestlist? The rest?
          // Use below for reference
          // shindy.whoseShindy = [User userWithName:[shindyInfo objectForKey:@"whoseShindy"] inManagedObjectContext:context];
      } else {
          shindy = [matches lastObject];
      }
  
      return shindy;
  }
  </code></pre>
  
  <p><strong>EDIT:</strong></p>
  
  <p>I suppose I should have also shown a file of which I have set as a subclass of my <code>HomeViewController</code>. It's basically the same thing as the code that is given to you to paste in the Apple Documentation</p>
  
  <p>CoreDataTableViewController.h</p>
  
  <pre><code>#import &lt;UIKit/UIKit.h&gt;
  #import &lt;CoreData/CoreData.h&gt;
  
  @interface CoreDataTableViewController : UITableViewController &lt;NSFetchedResultsControllerDelegate&gt;
  
  @property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
  
  - (void)performFetch;
  
  @property (nonatomic) BOOL suspendAutomaticTrackingOfChangesInManagedObjectContext;
  
  @property BOOL debug;
  
  @end
  </code></pre>
  
  <p>CoreDataTableViewController.m</p>
  
  <pre><code>@interface CoreDataTableViewController()
  @property (nonatomic) BOOL beganUpdates;
  @end
  
  @implementation CoreDataTableViewController
  
  #pragma mark - Properties
  
  @synthesize fetchedResultsController = _fetchedResultsController;
  @synthesize suspendAutomaticTrackingOfChangesInManagedObjectContext = _suspendAutomaticTrackingOfChangesInManagedObjectContext;
  @synthesize debug = _debug;
  @synthesize beganUpdates = _beganUpdates;
  
  - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  {
      return YES;
  }
  
  #pragma mark - Fetching
  
  - (void)performFetch
  {
      if (self.fetchedResultsController) {
          if (self.fetchedResultsController.fetchRequest.predicate) {
              if (self.debug) NSLog(@"[%@ %@] fetching %@ with predicate: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName, self.fetchedResultsController.fetchRequest.predicate);
          } else {
              if (self.debug) NSLog(@"[%@ %@] fetching all %@ (i.e., no predicate)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName);
          }
          NSError *error;
          [self.fetchedResultsController performFetch:&amp;error];
          if (error) NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]);
      } else {
          if (self.debug) NSLog(@"[%@ %@] no NSFetchedResultsController (yet?)", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
      }
      [self.tableView reloadData];
  }
  
  - (void)setFetchedResultsController:(NSFetchedResultsController *)newfrc
  {
      NSFetchedResultsController *oldfrc = _fetchedResultsController;
      if (newfrc != oldfrc) {
          _fetchedResultsController = newfrc;
          newfrc.delegate = self;
          if ((!self.title || [self.title isEqualToString:oldfrc.fetchRequest.entity.name]) &amp;&amp; (!self.navigationController || !self.navigationItem.title)) {
              self.title = newfrc.fetchRequest.entity.name;
          }
          if (newfrc) {
              if (self.debug) NSLog(@"[%@ %@] %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), oldfrc ? @"updated" : @"set");
              [self performFetch]; 
          } else {
              if (self.debug) NSLog(@"[%@ %@] reset to nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
              [self.tableView reloadData];
          }
      }
  }
  
  #pragma mark - UITableViewDataSource
  
  - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  {
      return [[self.fetchedResultsController sections] count];
  }
  
  - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  {
      return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
  }
  
  - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
  {
      return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
  }
  
  - (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
  {
      return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
  }
  
  - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
  {
      return [self.fetchedResultsController sectionIndexTitles];
  }
  
  #pragma mark - NSFetchedResultsControllerDelegate
  
  - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
  {
      if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext) {
          [self.tableView beginUpdates];
          self.beganUpdates = YES;
      }
  }
  
  - (void)controller:(NSFetchedResultsController *)controller
    didChangeSection:(id &lt;NSFetchedResultsSectionInfo&gt;)sectionInfo
             atIndex:(NSUInteger)sectionIndex
       forChangeType:(NSFetchedResultsChangeType)type
  {
      if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext)
      {
          switch(type)
          {
              case NSFetchedResultsChangeInsert:
                  [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
                  break;
  
              case NSFetchedResultsChangeDelete:
                  [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
                  break;
          }
      }
  }
  
  
  - (void)controller:(NSFetchedResultsController *)controller
     didChangeObject:(id)anObject
         atIndexPath:(NSIndexPath *)indexPath
       forChangeType:(NSFetchedResultsChangeType)type
        newIndexPath:(NSIndexPath *)newIndexPath
  {       
      if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext)
      {
          switch(type)
          {
              case NSFetchedResultsChangeInsert:
                  [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                  break;
  
              case NSFetchedResultsChangeDelete:
                  [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                  break;
  
              case NSFetchedResultsChangeUpdate:
                  [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                  break;
  
              case NSFetchedResultsChangeMove:
                  [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
                  [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
                  break;
          }
      }
  }
  
  - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
  {
      if (self.beganUpdates) [self.tableView endUpdates];
  }
  
  - (void)endSuspensionOfUpdatesDueToContextChanges
  {
      _suspendAutomaticTrackingOfChangesInManagedObjectContext = NO;
  }
  
  - (void)setSuspendAutomaticTrackingOfChangesInManagedObjectContext:(BOOL)suspend
  {
      if (suspend) {
          _suspendAutomaticTrackingOfChangesInManagedObjectContext = YES;
      } else {
          [self performSelector:@selector(endSuspensionOfUpdatesDueToContextChanges) withObject:0 afterDelay:0];
      }
  }
  
  @end
  </code></pre>
  
  <p>And then last, but not least, I have the header file for my HomeViewController of which I implement CoreDataTableViewController. Hopefully this is useful in better explaining what I've got.</p>
  
  <p>HomeViewController.h</p>
  
  <pre><code>#import &lt;UIKit/UIKit.h&gt;
  #import &lt;FacebookSDK/FacebookSDK.h&gt;
  #import "CoreDataTableViewController.h"
  
  @interface HomeViewController : CoreDataTableViewController
  
  @property (strong, nonatomic) UIManagedDocument *shindyDatabase;
  @property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
  
  @end
  </code></pre>