I'm implementing a UITableView with NSFetchedResultsController.
# D5ProductViewController.h
#interface D5ProductViewController : D5ViewControllerAbstract <UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate>
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong) D5Product *product;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
- (IBAction)addVariantTapped:(id)sender;
#end
# D5ProductViewController.m
#interface D5ProductViewController ()
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#end
#implementation D5ProductViewController
- (void)viewLoad {
NSError *error;
[self.fetcedResultsController performFetch:&error];
if (error) {
[self.alerts showError:[error localizedDescription]
:#"Error"];
}
}
#pragma mark - Properties
#synthesize managedObjectContext; // The context is passed from a parent view.
#synthesize fetchedResultsController = _fetchedResultsController;
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Variant"
inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entityDescription];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"price"
ascending:NO];
[fetchRequest setSortDescriptors:#[sortDescriptor]];
NSString *predicateString = [NSString stringWithFormat:#"productId = '%#' AND isMaster = 0", self.product.identifier];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
[fetchRequest setPredicate:predicate];
[fetchRequest setReturnsObjectsAsFaults:NO];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
#pragma mark - NSFetchedResultsControllerDelegate
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
[self.tableView reloadData];
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
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 configureCell:(D5VariantTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]
withObject:(D5Variant *)[controller objectAtIndexPath:indexPath]];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)configureCell:(D5VariantTableViewCell *)cell
withObject:(D5Variant *)variant {
cell.variant = variant;
}
#pragma mark - UITableViewDataSourceDelegate
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.fetchedResultsController.sections count];
}
#pragma mark - UITableViewDelegate
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
D5VariantTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:D5VariantCellReusableIdentifier
forIndexPath:indexPath];
D5Variant *variant = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.variant = variant;
cell.managedObjectContext = self.managedObjectContext;
return cell;
}
- (IBAction)addVariantTapped:(id)sender {
NSEntityDescription *variantEntityDescription = [NSEntityDescription entityForName:#"Variant"
inManagedObjectContext:self.managedObjectContext];
D5Variant *variant = [[D5Variant alloc] initWithEntity:variantEntityDescription
insertIntoManagedObjectContext:self.managedObjectContext];
variant.productId = self.product.identifier;
variant.price = [self.product.master price];
variant.weight = [self.product.master weight];
[variant markAsInserted];
NSError *error;
[self.fetchedResultsController performFetch:&error];
if (error) {
NSLog(#"%#", error);
}
[self.tableView reloadData];
}
#end
If I understand correctly, having implemented NSFetchedResultsController's controller:didChangeObject:atIndexPath:forChangeType:newIndexPath will cause UITableView to ask for a cell for the inserted row, which is configured with the object at the given indexPath from the fetchedResultsController.
The thing is that controller:didChangeObject...newIndexPath is never called when a new object is inserted in the managedObjectContext.
What am I missing? Do I need to call managedObjectContext's save method and then [self.tableView reloadData].
Thanks in advance!
Silly me, I forgot to set the UITableView's delegate:
The viewDidLoad method, besides setting the bindings, was just performing the fetch. Adding self.tableView.delegate = self; fixed the problem, BUT, isn't it enough setting the dataSource outlet in the IB? Which I already did. Why did I need to set the UITableView's delegate manually? In the case of the NSFetchedResultsController it needs to be set manually, but isn't it the purpose of the UITableView object having that outlet to just wire it up to the delegate object?
Anyways, setting self.tableView.delegate = self; fixed the problem.
Related
I have a Single View Application. It uses a ViewController embedded in a NavigationController. I have one UITextField and a UITableView added to the ViewController.
My model is extremely simple. It has two entities:
itemname
createdAt
I am able to create a new item without issue. When I look at the SQLite database, it do see the actual data being inserted correctly. My issue right now is that I cannot seem to figure out why the data is not being displayed in my UITableView.
ViewController.m
#import "ViewController.h"
#interface ViewController () <NSFetchedResultsControllerDelegate>
#property (strong) NSMutableArray *items;
#property(nonatomic, strong) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
// Update to handle the error appropriately.
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:#"Item" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"itemname" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"ItemCache"];
self.fetchedResultsController = theFetchedResultsController;
self.fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Item"];
self.items = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *item = [self.items objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [item valueForKey:#"itemname"]]];
[cell.detailTextLabel setText:[item valueForKey:#"itemname"]];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.items objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.items removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (IBAction)cancel:(id)sender {
//implement action here for cancel button to dismiss keyboard
}
- (IBAction)saveItem:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *newItem = [NSEntityDescription insertNewObjectForEntityForName:#"Item" inManagedObjectContext:context];
[newItem setValue:self.itemTextField.text forKey:#"itemname"];
NSLog(#"Creating new item");
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"updateItem"]) {
NSManagedObject *selectedItem = [self.items objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
ViewController *destViewController = segue.destinationViewController;
destViewController.itemTextField = selectedItem;
}
}
EDIT
Ive gone in and added my NSFetchedResultsController protocols.
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath]
atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
I seem to be getting an error on this line:
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath]
atIndexPath:indexPath];
break;
Does this need a datasource declared before tableView? If the UITableView is connected to the File Owner's datasource, should this be self?
I think it should actually look like this:
case NSFetchedResultsChangeUpdate:
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
You need to implement NSFetchedResultsControllerDelegate to handle changes to results, such as when entities are inserted into the store.
The delegate will update the tableView's model.
At the least, you simply could reload the table when your delegate was called.
inside perform fetch block, implement [tableView reloadData];
Just a caveat, this is my first ever question, be gentle with me.
I had a UITableViewController that conforms to the NSFetchedResultsControllerDelegate protocol. This all works perfectly. I want to change that to a UIViewController to be able to add more to the view than just the tableview. I created the tableView property and set the delegate and datasource. Everything works fine except that the FRC delegate methods are not called and the table is not updated. The inserts, edits, and deletes are being stored to the database, but the table is not updating when I change something in the context.
All the code is the basic template code for using a fetched results controller. When it sets the delegate in the line:
aFetchedResultsController.delegate = self;
It should be setting the delegate correctly, but it is not. Again, the only change I make is to remove the word Table from UITableViewController. It works with the UITableViewController but not the UIViewController. I have researched this extensively but have not found an answer.
Thanks.
Here's some code:
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
.
.
.
#class NowWhatDetailViewController;
#class Event;
#interface NowWhatMasterViewController : UITableViewController <NSFetchedResultsControllerDelegate, ChangeDateViewControllerDelgate, EditEventViewControllerDelgate, PasswordViewControllerDelegate,
UITableViewDelegate, UITableViewDataSource> {
NSMutableArray *saveButtonItems;
IBOutlet UILabel *nextEventLabel;
IBOutlet UILabel *timeToNextEventLabel;
}
#property (strong, nonatomic) NowWhatDetailViewController *detailViewController;
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, weak) id <ChangeDateViewControllerDelgate> delegate;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
.
.
.
#end
And the important sections of NowWhatMasterViewController.m
#import "NowWhatMasterViewController.h"
#interface NowWhatMasterViewController () {
}
#end
#implementation NowWhatMasterViewController {
Event *lastEditedEvent;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performFetch];
[[self.splitViewController.viewControllers lastObject] topViewController];
self.detailViewController.viewNSDate = self.viewNSDate;
self.detailViewController.viewDate = self.viewDate;
self.detailViewController.viewSchedule = self.viewSchedule;
self.detailViewController.managedObjectContext = self.managedObjectContext;
self.detailViewController.fetchedResultsControllerDetail = self.fetchedResultsController;
[self.detailViewController updateDetailView];
// show the bottom toolbar
[self.navigationController setToolbarHidden:NO];
saveButtonItems = [self.toolbarItems mutableCopy];
nextEventLabel.text = #"next event";
timeToNextEventLabel.text = #"starts in ## minutes";
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
self.fetchedResultsController = nil;
}
- (void)viewDidUnload {
self.fetchedResultsController = nil;
}
#pragma mark - Table View
/*
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [dayEvents count];
}
*/
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
Event *event = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self performSegueWithIdentifier:#"EditEvent" sender:event];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
return [sectionInfo numberOfObjects];
//return [dayEvents count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"EventCell"];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
if (_isLocked) {
return NO;
} else {
return YES;
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
[context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&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.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// The table view should not be re-orderable.
return NO;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
Event *event = [self.fetchedResultsController objectAtIndexPath:indexPath];
[event toggleChecked];
[self configureCheckmarkForCell:cell withEvent:event];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// this updates the detail controller when a row is selected. Not sure we want to do that
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
self.detailViewController.detailItem = object;
}
}
#pragma mark - Fetched results controller
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSLog(#"the fetched results controller is getting the events for %#", self.viewNSDate);
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Event" 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:#"eventNSDate" ascending:YES];
NSArray *sortDescriptors = #[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
// setup the predicate to return just the wanted date and schedule
NSPredicate *requestPredicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(eventDate like '%#') AND (schedule.scheduleName like '%#')", [Event returnDateString:self.viewNSDate], self.viewSchedule.scheduleName]];
[fetchRequest setPredicate:requestPredicate];
// Clear out any previous cache
[NSFetchedResultsController deleteCacheWithName:#"Master"];
// 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]) {
// 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.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
// manually set the delegate?
return _fetchedResultsController;
}
- (void)performFetch
{
NSError *error;
if (![self.fetchedResultsController performFetch:&error]) {
//FATAL_CORE_DATA_ERROR(error);
NSLog(#"database error");
return;
}
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
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
{
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:#[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:#[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
I want to delete record from my tableviewcontroller cell.
The code seems fine to me, the exception came when i press a row to delete...
this is my code of ViewController.h file
#import <UIKit/UIKit.h>
#interface IMSCategoryViewController : UITableViewController
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property(nonatomic,retain)NSArray *arr;
#property (readonly, strong, nonatomic) NSMutableArray *categoryArray;
#end
And This one in the implementation file.
#import "IMSCategoryViewController.h"
#import "IMSAppDelegate.h"
#import "Category.h"
#interface IMSCategoryViewController ()
{
NSManagedObjectContext *context;
}
#end
#implementation IMSCategoryViewController
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
#synthesize categoryArray;
#synthesize arr;
- (void)viewDidLoad
{
[super viewDidLoad];
// [self.tableView reloadData];
IMSAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
context = [appDelegate managedObjectContext];
NSEntityDescription *category = [NSEntityDescription entityForName:#"Category" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:category];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"is_active == 1"];
[request setPredicate:predicate];
[request setFetchBatchSize:25];
[request setEntity:category];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *srotDesc = [[NSArray alloc]initWithObjects:sort, nil];
[request setSortDescriptors:srotDesc];
NSError *error;
NSMutableArray *results = [[context executeFetchRequest:request error:&error] mutableCopy];
if (results == nil) {
//error handle here
}
[self setArr:results];
NSLog(#"there is category array");
[self.tableView reloadData];
[self.arr count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.arr count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Category *category = [self.arr objectAtIndex:indexPath.row];
// Configure the cell...
cell.textLabel.text = [category name];
cell.detailTextLabel.text = [category descript];
return cell;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
and where i am performing the delete action.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSManagedObject *recordtoDelete = [self.arr objectAtIndex:indexPath.row];
[_managedObjectContext deleteObject:recordtoDelete];
[self.tableView beginUpdates];
// Category *deleteRecord = [self.arr objectAtIndex:indexPath.row];
// [self.managedObjectContext deleteObject:deleteRecord];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
NSError *error = nil;
if (![_managedObjectContext save:&error]) {
//handle error here
}
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
OKAY So when i run this code...
it gives this type of error...
Terminating app due to uncaught exception `NSInternalInconsistencyException`,reason:
'Invalid update: invalid number of rows in section 0.
The number of rows contained in an existing section after the update (17) must be
equal to the number of rows contained in that section before the update (17),
plus or minus the number of rows inserted or deleted from that section
(0 inserted,1 deleted) and plus or minus the number of rows moved into or out of
that section (0 moved in, 0 moved out).
'
It's better to use NSFetchResultController than array, you can easily update tableView with NSFetchResultControllerDelgate. You only need 2 in a UItableViewController like this:
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
First Rewrite getter for NSFetchedResultController
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Category" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"is_active == 1"];
[fetchRequest setPredicate:predicate];
[fetchRequest setFetchBatchSize:25];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = #[sortDescriptor];
[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;
}
Rewrite datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
Category *category = (Category *)[self.fetchedResultsController objectAtIndexPath:indexPath];
// Configure the cell...
cell.textLabel.text = [category name];
cell.detailTextLabel.text = [category descript];
}
Delete
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
[context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
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
{
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:#[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:#[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
happy holidays!
so, Im grappling with coredata!, now I have info showing in a viewController in a table, but when I put the table in a second viewController called from the first, I get>
entityForName: could not locate an NSManagedObjectModel for entity name 'Contacts''
even though the code was working as mentioned before(in just one view), what shall I do?
thank you so much!
The little test project is
Here the project saves a contact (verified in a SQLite manager) but when taken to another view to check the contacts in a table it crashes, the part of the showing something of a db in a table inside the UIViewcontroller is working code also but in the main view not yet from this called xib, thanks
here the code, (show.h, the view loaded from the main view..)
#import <UIKit/UIKit.h>
#interface ShowViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate>
{
NSFetchedResultsController *_fetchedResultsController;
NSManagedObjectContext *_context;
UITableView *tableView;}
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) NSManagedObjectContext *context;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
-(IBAction) btnStart:(id) sender;
#end
(show.m)
#import "ShowViewController.h"
#import "Contacts.h"
#implementation ShowViewController
#synthesize context = _context;
#synthesize fetchedResultsController = _fetchedResultsController;
#synthesize tableView;
-(IBAction) btnStart:(id) sender{
initWithNibName:#"StartViewController" bundle:nil];
[UIView beginAnimations:#"flipping view" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
[UIView setAnimationTransition: UIViewAnimationTransitionCurlUp
forView:self.view.superview cache:YES];
[self.view removeFromSuperview];
[UIView commitAnimations];
}
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Contacts" inManagedObjectContext:_context];
[fetchRequest setEntity:entity];
//NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"details.closeDate" ascending:NO];
//[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:_context sectionNameKeyPath:nil cacheName:#"Root"];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
[fetchRequest release];
[theFetchedResultsController release];
return _fetchedResultsController;
}
- (void)viewDidLoad {
[super viewDidLoad];
/*array = [[NSMutableArray alloc] init];
[array addObject:#"Sports"];
[array addObject:#"Entertainment"];
[array addObject:#"Art"];
[array addObject:#"Technology"];*/
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
}
- (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 {
self.fetchedResultsController = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
//return [array count];
//return [[fetchedResultsController sections] count];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
Contacts *info = [_fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = info.name;
//cell.detailTextLabel.text = [NSString stringWithFormat:#"%#, %#", info.city, info.state];
}
//---insert individual row into the table view---
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
//---try to get a reusable cell---
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//---create new cell if no reusable cell is available---
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
- (void)dealloc {
self.fetchedResultsController = nil;
self.context = nil;
[super dealloc];
}
#pragma mark NSFetchedResultsControllerDelegate methods
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType: (NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
// Reloading the section inserts a new row and ensures that titles are updated appropriately.
[tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType: (NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}
#end
I've had this before, make sure your NSManagedObject is actually Contacts, check the spelling and check the case - usually typo
Please help me to fix this issue (Im getting crazy now!), My project is saving the data properly to the sqlite db in coredata, as checked in a SQLite grapical manager,but I dont seem to be able to show it in a table view, I need my table inside my viewController (small table not whole screen),
If you feel generous please check my little sample project
Here Thankyou!
here the code of the *viewcontroller.h
(Please note that I included a IBoutlet for the table view as tableView is not an instance in UIViewController!) was this done properly?,
also, I get 7 warnings where i call the tableView> Local declaration of 'tableView' hides instance variable
#import <UIKit/UIKit.h>
#interface CoreDataEnsaViewController : UIViewController
<UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate> //va controller delegate??
{
UITextField *name;
UITextField *address;
UITextField *phone;
UILabel *status;
//la table
//NSMutableArray *array;
//la tabla??
UITableView *tableView;
NSFetchedResultsController *_fetchedResultsController;
NSManagedObjectContext *_context;
}
#property (nonatomic, retain) IBOutlet UITextField *name;
#property (nonatomic, retain) IBOutlet UITextField *address;
#property (nonatomic, retain) IBOutlet UITextField *phone;
#property (nonatomic, retain) IBOutlet UILabel *status;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) NSManagedObjectContext *context;
- (IBAction) saveData;
- (IBAction) findContact;
- (IBAction) showbtn:(id) sender;
#end
and here the *viewController.m
#import "CoreDataEnsaViewController.h"
#import "CoreDataEnsaAppDelegate.h"
#import "ShowViewController.h"
#import "Contacts.h"
#implementation CoreDataEnsaViewController
ShowViewController *showView;
#synthesize name, address, phone, status, tableView;
#synthesize context = _context;
#synthesize fetchedResultsController = _fetchedResultsController;
-(IBAction) showbtn:(id) sender {
showView = [[ShowViewController alloc] initWithNibName:#"ShowViewController" bundle:nil];
//anima
[UIView beginAnimations:#"flipping view" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown
forView:self.view cache:YES];
[self.view addSubview:showView.view];
[UIView commitAnimations];
}
- (void) saveData
{
CoreDataEnsaAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newContact;
newContact = [NSEntityDescription insertNewObjectForEntityForName:#"Contacts" inManagedObjectContext:context];
[newContact setValue:name.text forKey:#"name"];
[newContact setValue:address.text forKey:#"address"];
[newContact setValue:phone.text forKey:#"phone"];
name.text = #"";
address.text = #"";
phone.text = #"";
NSError *error;
[context save:&error];
status.text = #"Contact saved";
}
- (void) findContact
{
CoreDataEnsaAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Contacts" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(name = %#)", name.text];
[request setPredicate:pred];
NSManagedObject *matches = nil;
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if ([objects count] == 0) {
status.text = #"No matches";
} else {
matches = [objects objectAtIndex:0];
address.text = [matches valueForKey:#"address"];
phone.text = [matches valueForKey:#"phone"];
status.text = [NSString stringWithFormat:#"%d matches found", [objects count]];
}
[request release];
}
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Contacts" inManagedObjectContext:_context];
[fetchRequest setEntity:entity];
//NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"details.closeDate" ascending:NO];
//[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:_context sectionNameKeyPath:nil cacheName:#"Root"];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
[fetchRequest release];
[theFetchedResultsController release];
return _fetchedResultsController;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
- (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 {
self.name = nil;
self.address = nil;
self.phone = nil;
self.status = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
//tabla
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
//return [array count];
//return [[fetchedResultsController sections] count];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
Contacts *info = [_fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = info.name;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#, %#", info.address, info.phone];
}
//---insert individual row into the table view---
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
//---try to get a reusable cell---
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//---create new cell if no reusable cell is available---
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
//tabla end
- (void)dealloc {
[name release];
[address release];
[phone release];
[status release];
self.fetchedResultsController = nil;
self.context = nil;
[super dealloc];
}
#pragma mark NSFetchedResultsControllerDelegate methods
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
// Reloading the section inserts a new row and ensures that titles are updated appropriately.
[tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
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)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];}
#end
The connections in the xib are>
table view
outlet:
data source-----------files owner;
delegate--------------files owner;
referencing outlets
tableView-------------files owner;
thank you so much!!!!
As for the "NSInternalConsistencyException" check the managed object model against your code and make sure you're calling it exactly right. Failing that, have you done a clean, restarted XCode, restarted your computer, deleted app from simulator, the usual stuff? If you've made changes to the file or swapped it out, the old stuff will sometimes "lurk" and cause these issues. Failing that, sometimes when I've had a confounding core data problem, rebuilding the model file from scratch and auto-creating the subclasses over will fix it...don't know why.
I know this wasn't your question, but it's widely discouraged to simply call the app delegate for the managed object context--though it does work and you'll see it in some code examples, it's not best practice. It introduces an unnecessary dependency in your project which will make your code harder to maintain. The app delegate should only be used to handle system-level events as it was designed, not "abused" for other purposes. The better way is to create a managed object context property for each controller that needs it, and pass the reference when that controller is created. Your App Delegate will pass it to the root view controller in didFinishLaunchingWithOptions (simply by setting the receiving controller's property), like this:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions...
{
UINavigationController *navController = self.window.rootViewController
MyViewController *controller = navController.viewControllers[0];
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
When that root view controller needs to pass the MOC to another controller, it happens like this:
-(void)prepareForSegue...
{
MyOtherController *otherController = [segue destinationViewController];
controller.managedObjectContext = self.managedObjectContext;
}
And so on and so forth, for each controller that needs it. That way you aren't introducing unnecessary dependencies that make your code less modular and reusable.
Hope this helped.
Try to add this code to perform a fetch of data in your viewDidLoad method:NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unsolved error: %#, %#", error, [error userInfo]);
abort();
}