In this screencast I'll pull down data from an API, map the JSON to a Core Data Managed Object and import them in bulk on a background thread. Then we'll display the imported content in a UITableView using NSFetchedResultsController.
Episode Links Episode Source Code NSFetchedResultsController class reference This project requires mogenerator to be installed. You can install it with homebrew: brew install mogenerator Having mogenerator invoked automatically after each build Add a new Run-Script Build Phase with the following contents: MODELS_DIR="BeerBrowser/DataModel" DATA_MODEL_PACKAGE="$MODELS_DIR/Beers.xcdatamodeld" CURRENT_VERSION=`/usr/libexec/PlistBuddy "$DATA_MODEL_PACKAGE/.xccurrentversion" -c 'print _XCCurrentVersionName'` mogenerator --template-var arc=true --model "$DATA_MODEL_PACKAGE/$CURRENT_VERSION" --output-dir "$MODELS_DIR/" Core Data-friendly nil support on NSDictionary #import "NSDictionary+ObjectForKeyOrNil.h" @implementation NSDictionary (ObjectForKeyOrNil) - (id)objectForKeyOrNil:(id)key { id val = [self objectForKey:key]; if ([val isEqual:[NSNull null]]) { return nil; } return val; } @end Mapping from JSON to Core Data This is a manual approach to mapping from JSON objects. It's also possible to devise a more "clever" convention-based scheme. - (void)updateAttributes:(NSDictionary *)attributes { self.name = [attributes objectForKeyOrNil:@"name"]; self.address1 = [attributes objectForKeyOrNil:@"address1"]; self.address2 = [attributes objectForKeyOrNil:@"address2"]; self.city = [attributes objectForKeyOrNil:@"city"]; self.state = [attributes objectForKeyOrNil:@"state"]; self.country = [attributes objectForKeyOrNil:@"country"]; self.postalCode = [attributes objectForKeyOrNil:@"postalCode"]; self.details = [attributes objectForKeyOrNil:@"description"]; self.website = [attributes objectForKeyOrNil:@"website"]; } Fetching an entity by a property + (Brewery *)breweryWithServerId:(NSInteger)serverId usingManagedObjectContext:(NSManagedObjectContext *)moc { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[Brewery entityName]]; [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"serverId = %d", serverId]]; [fetchRequest setFetchLimit:1]; NSError *error = nil; NSArray *results = [moc executeFetchRequest:fetchRequest error:&error]; if (error) { NSLog(@"ERROR: %@ %@", [error localizedDescription], [error userInfo]); exit(1); } if ([results count] == 0) { return nil; } return [results objectAtIndex:0]; } Fetched results controller initialization - (void)loadBreweries { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[Brewery entityName]]; [fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:@"name", @"city", @"state", @"country", nil]]; [fetchRequest setFetchBatchSize:40]; NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortByName]]; _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[[BeersDataModel sharedDataModel] mainContext] sectionNameKeyPath:nil cacheName:nil]; [_fetchedResultsController performFetch:nil]; } Listening for changes to a background Managed Object Context // in viewDidLoad... [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:nil]; - (void)contextDidSave:(NSNotification *)notification { dispatch_async(dispatch_get_main_queue(), ^{ NSManagedObjectContext *mainContext = [[BeersDataModel sharedDataModel] mainContext]; [mainContext mergeChangesFromContextDidSaveNotification:notification]; [self loadBreweries]; [self.tableView reloadData]; }); } Implementing the UITableViewDataSource methods with NSFetchedResultsController - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [[_fetchedResultsController sections] count]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { id<NSFetchedResultsSectionInfo> sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section]; return [sectionInfo numberOfObjects]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { Brewery *brewery = [_fetchedResultsController objectAtIndexPath:indexPath]; /* Standard UITableViewCell stuff */ return cell; }