+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name - objective-c

What I'm trying to do: Get an NSFetchedResultsController to work for the first time to connect a UITableView to Core Data. I'm a newbie and really inexperienced, and I've followed Ray Wenderlich's Tutorial word to word.
The error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Medicine''`.
What I tried: None of the other StackOverflow questions that I found (including
this and this) have the an explanation, except for the second one which makes some sense. However, the method he mentioned is already written in my app delegate, which I imported in the TableViewController class I'm using.
What I'd greatly appreciate: An explanation of what I'm doing/what's gone wrong and how to fix it, rather than just the answer/correction.
PMMedicinesTableViewController.m
#import "PMMedicinesTableViewController.h"
#import "PMAppDelegate.h"
#import "Medicine.h"
#interface PMMedicinesTableViewController ()
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#end
#implementation PMMedicinesTableViewController
#synthesize fetchedResultsController = _fetchedResultsController;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
}
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Medicine" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:#"name" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
cacheName:#"Root"];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id sectionInfo =
[[_fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
Medicine *med = [_fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = med.name;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",
med.name];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"medicineCellIdentifier" forIndexPath:indexPath];
// Set up the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Thanks in advance!

The error is telling you that self.managedObjectContext is nil, which means that you haven't assigned a value to that property. Most likely you should have done this in whatever code created or loaded this view controller (e.g. in prepareForSegue:sender: if you're using storyboards).

Related

'NSInternalInconsistencyException', reason: 'attempt to insert row 3 into section 0, but there are only 2 rows in section 0 after the update'

I use Core Data in my project and when trying to add new row, I get an error:
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3318.16.14/UITableView.m:1377
2015-01-16 22:45:47.172 LinguaCard[26439:599761] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert row 3 into section 0, but there are only 2 rows in section 0 after the update'
CardsTableViewController.m
#import "CardsTableViewController.h"
#import "Lesson.h"
#import "Card.h"
#import "CoreDataHelper.h"
#interface CardsTableViewController ()
#property (strong, nonatomic) NSMutableArray *cards;
#end
#implementation CardsTableViewController
-(NSMutableArray *)cards{
if (!_cards)
_cards = [[NSMutableArray alloc] init];
return _cards;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSSet *unordereCards = self.lesson.cards;
NSSortDescriptor *nameDescr = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES];
NSArray *sortedCards = [unordereCards sortedArrayUsingDescriptors:#[nameDescr]];
self.cards = [sortedCards mutableCopy];
#pragma mark - helpers
-(Card *)cardWithName:(NSString *)name{
NSManagedObjectContext *context = [CoreDataHelper managedObjectContext];
Card *card = [NSEntityDescription insertNewObjectForEntityForName:#"Card" inManagedObjectContext:[CoreDataHelper managedObjectContext]];
card.name = name;
card.lesson = self.lesson;
NSError *error = nil;
if (![context save:&error]){
//we have an error
NSLog(#"error: %#", error);
}
return card;
}
#pragma mark - UIAlertViewDelegate
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 1) {
NSString *alertText = [alertView textFieldAtIndex:0].text;
[self.cards addObject:[self cardWithName:alertText]];
[self.tableView insertRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:[self.cards count]-1 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
}
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Card"];
NSError *error = nil;
NSArray *fetchedCards = [[CoreDataHelper managedObjectContext] executeFetchRequest:fetchRequest error:&error];
self.cards = [fetchedCards mutableCopy];
[self.tableView reloadData];
}
- (IBAction)addCard:(id)sender {
UIAlertView *newCard = [[UIAlertView alloc] initWithTitle:#"Enter new card name:" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Add", nil];
[newCard setAlertViewStyle:UIAlertViewStylePlainTextInput];
[newCard show];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.lesson.cards.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Card Cell" forIndexPath:indexPath];
Card *selectedCard = self.cards[indexPath.row];
cell.textLabel.text = selectedCard.name;
return cell;
}
When your UIAlertViewDelegate method adds a card it adds it to a controller property. When you report the number of rows in your section you use the lesson object which doesn't know about the controller's cards.

Use of undeclared identifier 'location'

Am getting this error on several lines which I have commented out, and wonder why I am getting this problem? What is the best way to fix this?
Location is a CoreData entity and placemark is one of its attributes.
Thanks in advance.
LocationsViewController.m
#import "LocationsViewController.h"
#import "Location.h"
#interface LocationsViewController ()
#end
#implementation LocationsViewController{
NSArray *locations;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Location" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSError *error;
NSArray *foundObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (foundObjects == nil) {
FATAL_CORE_DATA_ERROR(error);
return;
}
locations = foundObjects;
}
- (void)viewDidUnload
{
[super viewDidUnload];
locations = nil;
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [locations count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Location"];
UILabel *descriptionLabel = (UILabel *) [cell viewWithTag:100];
descriptionLabel.text = #"If you can see this";
UILabel *addressLabel = (UILabel *)[cell viewWithTag:101];
addressLabel.text = #"%# %#, %#",
location.placemark.subThoroughfare, // Use of undeclared identifier 'location'
location.placemark.thoroughfare, // Use of undeclared identifier 'location'
location.placemark.locality ]; // Use of undeclared identifier 'location'
return cell;
}
#end
In cellForRowAtIndexPath
You forgot
Location *location = locations[indexPath.row];

NSFetchedResultsController doesn't fetch results even though items are created in the database

I'm new to iOS, so apologies if this is brain dead simple... I've been iteratively working through some small proof of concept apps before starting to implement my full app so that it wouldn't be as overwhelming. I had my table view working fine when I created it following the "Your Second iOS App" tutorial on the Apple website. Now I've tried creating it in a tab bar app though, and I'm seeing problems with the NSFetchedResultsController, and I'm not sure if it's related to something that I'm doing wrong in the Storyboard, or something else.
I have a Tab Bar Controller that connects to a Table View Controller (CatalogViewController.h/m) that is embedded in a Navigation Controller. The Table View Controller is configured to have static cells. In the first static cell I have a push segue to another Table View Controller (FoodCatalogViewController.h/m) which is configured to use dynamic prototypes - this is the view in which I expect to see the objects from my database (from the Food entity - currently just shows name and calories). This view has an "Add" button to create new entries in the database - the add button has a modal segue to another static table view (AddFoodViewController.h/m) that is embedded in it's own navigation controller. I know that the "Add" button is working and that it's view is correctly connecting to the database (i.e. I'm passing/setting the NSManagedObjectContext correctly), because if I open the app's sqlite database file using "SQLite Database Browser", I see the items that I've added in the simulator. I just don't understand why they're not getting displayed in my table view via the NSFetchedResultsController. I stepped through the code using breakpoints and confirmed that the performFetch code is being called in my FoodCatalogViewController's fetchedResultsController function. I added a debug NSLog line in the numberOfRowsInSection code, and it seems to be nil, so I never get into cellForRowAtIndexPath or configureCell. So it looks like the NSFetchedResultsController is the culprit - I just don't know why it's not fetching the results correctly, and what I can do to debug this further. Can anyone help me with this?
In order to pass the Core Data info through the hierarchy, I have the following code snippets:
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
// Setup the Catalogs Tab
UINavigationController *navigationController = [[tabBarController viewControllers] objectAtIndex:0];
CatalogViewController *catalogViewController = [[navigationController viewControllers] objectAtIndex:0];
catalogViewController.managedObjectContext = self.managedObjectContext;
return YES;
}
CatalogViewController.m (the first table view controller in the sequence - I pass the NSManagedObjectContext through to it):
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"BrowseFoodCatalog"]) {
[[segue destinationViewController] setManagedObjectContext:self.managedObjectContext];
}
}
FoodCatalogViewController.h (the second table view controller in the sequence - I use the NSManagedObjectContext to setup the NSFetchedResultsController):
#interface FoodCatalogViewController : UITableViewController <NSFetchedResultsControllerDelegate>
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
- (void) addFoodWithName:(NSString *)name calories:(NSNumber *)calories;
#end
FoodCatalogViewController.m (the second table view controller in the sequence - I use the NSManagedObjectContext to setup the NSFetchedResultsController):
#interface FoodCatalogViewController () <AddFoodViewControllerDelegate>
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
#end
#implementation FoodCatalogViewController
#synthesize fetchedResultsController = __fetchedResultsController;
#synthesize managedObjectContext = __managedObjectContext;
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil) {
return __fetchedResultsController;
}
// Set up the fetched results controller.
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Food" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Master"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __fetchedResultsController;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"FoodCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:#"name"] description];
NSNumber *calorieNum = [managedObject valueForKey:#"calories"];
cell.detailTextLabel.text = [[calorieNum stringValue] description];
}
Additional Info
Not sure if this is relevant, but in order to get CoreData to automatically be included in my project, I started with the Single View template, but modified it's TemplateInfo.plist to add the following line under the similar line for storyboarding:
<string>com.apple.dt.unit.coreDataCocoaTouchApplication</string>
I'd found this online somewhere in someone's forum or something. Could this have messed up the CoreData somehow?
Additional Code
As requested, here's the code that I use to add new elements to the database:
AddFoodViewController.h:
#import <UIKit/UIKit.h>
#protocol AddFoodViewControllerDelegate;
#interface AddFoodViewController : UITableViewController <UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *foodNameInput;
#property (weak, nonatomic) IBOutlet UITextField *caloriesInput;
#property (weak, nonatomic) id <AddFoodViewControllerDelegate> delegate;
- (IBAction)save:(id)sender;
- (IBAction)cancel:(id)sender;
#end
#protocol AddFoodViewControllerDelegate <NSObject>
- (void)addFoodViewControllerDidCancel:(AddFoodViewController *)controller;
- (void)addFoodViewControllerDidSave:(AddFoodViewController *)controller name:(NSString *)name calories:(NSNumber *)calories;
#end
AddFoodViewController.m:
#import "AddFoodViewController.h"
#implementation AddFoodViewController
#synthesize foodNameInput;
#synthesize caloriesInput;
#synthesize delegate = _delegate;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload
{
[self setFoodNameInput:nil];
[self setCaloriesInput:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ((textField == self.foodNameInput) || (textField == self.caloriesInput )) {
[textField resignFirstResponder];
}
return YES;
}
- (IBAction)save:(id)sender {
int caloriesInt = [self.caloriesInput.text intValue];
NSNumber *caloriesNum = [NSNumber numberWithInt:caloriesInt];
[[self delegate] addFoodViewControllerDidSave:self name:self.foodNameInput.text calories:caloriesNum];
}
- (IBAction)cancel:(id)sender {
[[self delegate] addFoodViewControllerDidCancel:self];
}
#end
FoodCatalogViewController.m (the AddFoodViewControllerDelegate protocol code to add to the database):
- (void)addFoodViewControllerDidCancel:(AddFoodViewController *)controller {
[self dismissViewControllerAnimated:YES completion:NULL];
}
- (void)addFoodViewControllerDidSave:(AddFoodViewController *)controller name:(NSString *)name calories:(NSNumber *)calories {
if ([name length]) {
[self addFoodWithName:name calories:calories];
[[self tableView] reloadData];
}
[self dismissModalViewControllerAnimated:YES];
}
- (void) addFoodWithName:(NSString *)name calories:(NSNumber *)calories {
// Create a new instance of the entity managed by the fetched results controller.
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSLog(#"entity name is %#", [entity name]);
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
// If appropriate, configure the new managed object.
// Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
[newManagedObject setValue:name forKey:#"name"];
[newManagedObject setValue:calories forKey:#"calories"];
CFUUIDRef uuidRef = CFUUIDCreate(NULL);
CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
NSString* uuid = [NSString stringWithString:(__bridge NSString *)uuidStringRef];
[newManagedObject setValue:uuid forKey:#"uuid"];
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
More Debug Info
Strange - it looks like the fetchedResultsController isn't working correctly in the FoodCatalogViewController even though the managedObjectContext seems to be working... Here's the modified fetchedResultsController function from FoodCatalogViewController.m with some debug NSLog statements and replacing self.fetchedResultsController with __fetchedResultsController (because I wondered if that was causing the problem).
Here's the output from the fetchedResultsController function NSLog calls:
2012-01-29 10:22:21.118 UltraTrack[19294:fb03] Result: (
"<Food: 0x6e651b0> (entity: Food; id: 0x6e64630 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p1> ; data: <fault>)",
"<Food: 0x6e653e0> (entity: Food; id: 0x6e61870 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p3> ; data: <fault>)",
"<Food: 0x6e65450> (entity: Food; id: 0x6e64420 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p4> ; data: <fault>)",
"<Food: 0x6e654c0> (entity: Food; id: 0x6e64430 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p5> ; data: <fault>)",
"<Food: 0x6e65530> (entity: Food; id: 0x6e64e80 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p2> ; data: <fault>)",
"<Food: 0x6e655b0> (entity: Food; id: 0x6e64e90 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p6> ; data: <fault>)"
)
2012-01-29 10:22:21.907 UltraTrack[19294:fb03] Number or objects: 6
And here's the modified fetchedResultsController function:
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil) {
return __fetchedResultsController;
}
// Set up the fetched results controller.
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Food" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Master"];
aFetchedResultsController.delegate = self;
__fetchedResultsController = aFetchedResultsController;
NSArray *result = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
NSLog(#"Result: %#", result);
NSError *error = nil;
if (![__fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
NSLog(#"Number or objects: %d", [__fetchedResultsController.fetchedObjects count]);
return __fetchedResultsController;
}
Someone suggested that the sections were the problem, so I hard-coded numberOfSectionsInTableView to return 1, and then the first object from the fetchResults seems to be handled correctly, but I get the following exception:
2012-01-29 10:29:27.296 UltraTrack[19370:fb03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 1 in section at index 0'
If I hardcode numberOfRowsInSection to also return 1, then the first object from my database is correctly displayed in the table view. What could be the problem with regard to the sections info in the fetchedResultsController? Could I have setup something incorrectly in the storyboard for the table view with regard to sections?
Here's the 2 table view functions where I've tried the hard-coding:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
//NSLog(#"Number of sections in table view is %d", [[self.fetchedResultsController sections] count]);
//return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Number or objects: %d", [self.fetchedResultsController.fetchedObjects count]);
// If I return 1, the object is displayed correctly, if I return count, I get the exception
//return 1;
return [self.fetchedResultsController.fetchedObjects count];
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
NSLog(#"Number of rows being returned is %d", [sectionInfo numberOfObjects]);
return [sectionInfo numberOfObjects];
}
From your description it seems that the code with the sections is the culprit. But you are not actually using any sections. So try this to simplify:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.fetchedResultsController.fetchedObjects count];
}
If this still returns zero rows, check your fetchedObjects.count in the fetchedResultsController getter method.

managedObjectContext save issue

Over the last few days, I've searched far and wide and followed every resolution I could find online with no success.
Basically, I'm refreshing a Core Data entity from JSON data I pull from the web. I can clear out the previous data pulled from the web and load in the new data. The problem occurs when I attempt to save to Core Data "[self.managedObjectContext save:&error];".
The app just locks up.
The code from my view controller is shown below. I would greatly appreciate any assistance.
** CODE ***
//
// ChargeEntryViewController.m
// pcc
//
// Created by Tim Black on 3/14/11.
// Copyright 2011 Mobile Intents. All rights reserved.
//
#import "ChargeEntryViewController.h"
#import "pccAppDelegate.h"
#import "ChargeEntryPatientViewController.h"
#import "CJSONDeserializer.h"
#interface ChargeEntryViewController (PrivateMethods)
- (NSString *)jsonFromURLString:(NSString *)urlString;
- (void)handleError:(NSError *)error;
#end
#implementation ChargeEntryViewController
#synthesize fetchedResultsController=fetchedResultsController_;
#synthesize managedObjectContext=managedObjectContext_;
#synthesize providerArray;
#synthesize clearBtn;
#synthesize setBtn;
#synthesize patientController;
#pragma mark - Button methods
-(IBAction) clearAll:(id)sender{
selRow = -1;
[providerList reloadData];
}
-(IBAction) setPatientView:(id)sender {
if (self.patientController == nil) {
ChargeEntryPatientViewController *tmpController = [[ChargeEntryPatientViewController alloc] initWithNibName:#"ChargeEntryPatientView" bundle:nil];
self.patientController = tmpController;
[tmpController release];
}
patientController.title = #"Patient Selection";
[self.navigationController pushViewController:patientController animated:YES];
}
/*
Used to refresh the providers list from nrhsportal
*/
-(void)refreshProviders {
NSError *error = nil;
// get provider code from app delegate
pccAppDelegate *appDelegate = (pccAppDelegate *)[[UIApplication sharedApplication] delegate];
// first, clear out current list stored locally
NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
[fetch setEntity:[NSEntityDescription entityForName:#"Provider" inManagedObjectContext:self.managedObjectContext]];
NSArray *result = [self.managedObjectContext executeFetchRequest:fetch error:&error];
if (error != nil) {
[self handleError:error];
return;
}
for (id basket in result) {
[self.managedObjectContext deleteObject:basket];
}
// add (My Patients) entry
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:#"Provider" inManagedObjectContext:self.managedObjectContext];
[newManagedObject setValue:#"(My Patients)" forKey:#"fullname"];
[self.managedObjectContext insertObject:newManagedObject];
NSString *code = appDelegate.groupCode;
// create remote source URI
NSString *urlString = [NSString stringWithFormat:#"%s%#%s", "https://nrhsportal.nrh-ok.com/pccdata.svc/GetProviders?groupcode='", code, "'&$format=json"];
NSLog(#"URL String %#", urlString);
// Perform HTTP GET to the REST web service which returns JSON
NSString *jsonString = [self jsonFromURLString:urlString];
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF32BigEndianStringEncoding];
// Parse JSON results to convert to a dictionary
CJSONDeserializer *jsonDeserializer = [CJSONDeserializer deserializer];
error = nil;
NSDictionary *resultsDictionary = [jsonDeserializer deserializeAsDictionary:jsonData error:&error];
if (error != nil) {
[self handleError:error];
return;
}
// Traverse through returned dictionary to populate tweets model
NSDictionary *topArray = [resultsDictionary objectForKey:#"d"];
NSArray *resultsArray = [topArray objectForKey:#"results"];
for (NSDictionary *resultDictionary in resultsArray) {
// create the
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:#"Provider" inManagedObjectContext:self.managedObjectContext];
NSString *providerName = [resultDictionary objectForKey:#"fullname"];
[newManagedObject setValue:providerName forKey:#"fullname"];
[self.managedObjectContext insertObject:newManagedObject];
}
error = nil;
[self.managedObjectContext save:&error];
if (error != nil) {
[self handleError:error];
return;
}
[newManagedObject release];
[result release];
}
// This will issue a request to a web service API via HTTP GET to the URL specified by urlString.
// It will return the JSON string returned from the HTTP GET.
- (NSString *)jsonFromURLString:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"GET"];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
[request release];
[self handleError:error];
NSString *resultString = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
return [resultString autorelease];
}
// This shows the error to the user in an alert.
- (void)handleError:(NSError *)error {
if (error != nil) {
UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:#"Error" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil];
[errorAlertView show];
[errorAlertView release];
}
}
#pragma mark - View lifecycle
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
selRow = -1;
// refresh the provider list from remote data
[self refreshProviders];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:#"fullname"] description];
cell.textLabel.font=[UIFont systemFontOfSize:16.0];
if ([cell.textLabel.text isEqualToString: #"(My Patients)"]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:YES];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// Reflect selection in data model
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
// Reflect deselection in data model
}
}
#pragma mark - Fetched results controller
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController_ != nil) {
return fetchedResultsController_;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Provider" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"fullname" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController_;
}
#pragma mark - Memory management
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc
{
[patientController release];
[clearBtn release];
[setBtn release];
[providerArray release];
[fetchedResultsController_ release];
[managedObjectContext_ release];
[super dealloc];
}
#end
You don't need the line
[self.managedObjectContext insertObject:newManagedObject];
since you've already insertNewObjectForEntityForName before with the newManagedObject.

NSCFString objectAtIndex unrecognized selector sent to instance 0x5d52d70

I'm new to iPhone development, and been having a hard time trying to figure out why my table isn't working. It could be something with Core Data, I'm not sure. The viewDidLoad method works fine at the start, but when I try to scroll the table view, when a next row appears, I get the error:
NSInvalidArgumentException', reason: '-[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x5d52d70'
my View Controller.h:
#import <UIKit/UIKit.h>
#define kTableViewRowHeight 66
#interface RostersViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource> {
NSArray *objects;
}
#property(nonatomic,retain) NSArray *objects;
#end
my View Controller.m:
#import "RostersViewController.h"
#import "CogoAppDelegate.h"
#import "TeamCell.h"
#implementation RostersViewController
#synthesize objects;
- (void)viewDidLoad {
CogoAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Teams" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
NSError *error;
objects = [context executeFetchRequest:request error:&error];
if (objects == nil)
{
NSLog(#"There was an error!");
// Do whatever error handling is appropriate
}
[request release];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:app];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[objects release];
[super dealloc];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [objects count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
id currObj = [objects objectAtIndex:indexPath.row];
cell.textLabel.text = [currObj valueForKey:#"name"];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return kTableViewRowHeight;
}
#end
Thanks for any help. It's very much appreciated.
In viewDidLoad change objects = [context executeFetchRequest:request error:&error]; to self.objects = [context executeFetchRequest:request error:&error];
executeFetchRequest returns an autoreleased object, which you are then storing directly to the ivar, this turns into a garbage pointer at a later point. Which just so happens to end up pointing to a string.
Using self.objects makes it use the synthesized setter and will retain it.