Refreshing table view using core data - ios

I am having issues reloading my core data after inserting a new item I have tried the following however no joy. I was wondering if this could be due to the way i am calling the data? Im very new to this and have been following various tutorials to come this far however im stuck now. I know the viewdidappear is being called as nslog states this however the table is not updated
`- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self.tableView reloadData];
NSLog (#"did appear");
}`
Any Ideas?
// ViewController.m
// Core Data
#import "ViewController.h"
#import "AppDelegate.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UINavigationItem *back;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) NSMutableArray *name;
#property (strong, nonatomic) NSMutableArray *phone;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.name = [[NSMutableArray alloc] init];
self.phone = [[NSMutableArray alloc] init];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Contact" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
// NSPredicate *pred =[NSPredicate predicateWithFormat:#"(name = %#)", #"Vea Software"];
// [request setPredicate:pred];
NSManagedObject *matches = nil;
NSError *error;
NSArray *objects = [context executeFetchRequest:request
error:&error];
if ([objects count] == 0)
{
NSLog(#"No matches");
}
else
{
for (int i = 0; i < [objects count]; i++)
{
matches = objects[i];
[self.name addObject:[matches valueForKey:#"name"]];
[self.phone addObject:[matches valueForKey:#"phone"]];
}
}
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self.tableView reloadData];
NSLog (#"did appear");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)add:(id)sender
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newContact;
newContact = [NSEntityDescription insertNewObjectForEntityForName:#"Contact" inManagedObjectContext:context];
addentry = self.addtextbox.text;
[newContact setValue: addentry forKey:#"name"];
[self.name addObject: addentry];
[newContact setValue: #"(555) 555 - 5555" forKey:#"phone"];
[self.phone addObject:#"(555) 555 - 5555"];
NSError *error;
[context save:&error];
[self.tableView reloadData];
}
#pragma Table View
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.name.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
cell.textLabel.text = [self.name objectAtIndex:indexPath.row];
return cell;
}
#end

Take a look at this tutorial http://www.raywenderlich.com/999/core-data-tutorial-for-ios-how-to-use-nsfetchedresultscontroller
You need to rethink the architecture of your view controller. In general, you want to:
have the view controller load the data, and just "sit there" waiting to receive a notification that things have changed, and reload based on that notification. This is the "UI thread", that should not be blocked by data-access operations
have your data changes occurring on the background. Modern apps use Grand Central Dispatch to make these operations on the background, but there are other alternatives, like NSOperation, threads, etc.
Let the NSFetchedResultsController handle the UI updates for you. Let Core Data contexts manage the data consolidation.
These two concepts are key to make things work as they should. Otherwise, you may end up with a mess of code.
Good luck!

Related

CoreData + UIViewController + UITableView

I would like to explain the most detailed the problem I'm facing.
Previously instead of the UIViewController i had directly a UITableViewController, the problem is that now i need to show more content in the view that just the tableview so i created a new view. Now i have a UIViewController that has: UIScrollView. Enside of it there are: 1. UIView + 1 UITableView
I'm using AutoLayout. And is working fine. The problem I'm facing is that since i switched to use this view I'm unable to display content in the table with coredata. I was able to do it without coredata but not with it.
In the interfacebuilder i set datasource and delegate to this UIViewController.
Header:
#import <UIKit/UIKit.h>
#interface ResultsExtraVC : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property(nonatomic, strong) AGTCoreDataStack *model;
#property (strong, nonatomic) IBOutlet UILabel *labelRaceTime;
#property (strong, nonatomic) IBOutlet UILabel *labelTrackCondition;
#property (strong, nonatomic) IBOutlet UILabel *labelRaceStarttime;
#property (strong, nonatomic) IBOutlet UILabel *labelRaceMode;
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) IBOutlet UIView *raceInfoView;
#property(nonatomic, strong)NSNumber *eventID;
#property(nonatomic, strong)NSNumber *sectionID;
#property(nonatomic, strong)NSNumber *elementID;
#property(nonatomic, strong)NSNumber *categoryID;
#end
Implementation:
#import "ResultsExtraVC.h"
#import "ResultsExtraCellVC.h"
#import "Result.h"
#import "Element.h"
#import "Section.h"
#import <CoreData/CoreData.h>
#interface ResultsExtraVC () <NSFetchedResultsControllerDelegate>
//Core data
#property (nonatomic,strong) NSManagedObjectContext* managedObjectContext;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#end
static NSString * const cellIdentifier = #"resultsExrtaAltCell";
#implementation ResultsExtraVC
#synthesize managedObjectContext;
#synthesize fetchedResultsController = _fetchedResultsController;
#synthesize eventID, sectionID, elementID, categoryID, model;
- (void)viewDidLoad {
[super viewDidLoad];
managedObjectContext = self.model.context;
[self getResults];
NSLog(#"ElementName: %#", [self getElementName]);
NSLog(#"SectionName: %#", [self getSectionName]);
[self configureHeatInfo];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.fetchedResultsController = nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - View Configuration
-(void) configureHeatInfo{
_scrollView.backgroundColor = [UIColor cyanColor];
_scrollView.translatesAutoresizingMaskIntoConstraints = NO;
_labelRaceTime.translatesAutoresizingMaskIntoConstraints = NO;
_labelRaceTime.text = #"Race time:\n10:00";
_labelRaceMode.translatesAutoresizingMaskIntoConstraints = NO;
_labelRaceMode.text = #"Mode: Groupstart";
_labelTrackCondition.translatesAutoresizingMaskIntoConstraints = NO;
_labelTrackCondition.text = #"Track Condition: Dry";
_labelRaceStarttime.translatesAutoresizingMaskIntoConstraints = NO;
_labelRaceStarttime.text = #"Starttime: 12.03.2016 11:09:10";
//self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
/*self.tableView.dataSource = self;
self.tableView.delegate = self;*/
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.fetchedResultsController sections] count];
}
/*- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}*/
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
#ifndef NDEBUG
NSLog(#"%s (line:%d) - Rows: %lu",__PRETTY_FUNCTION__,__LINE__, (unsigned long)[sectionInfo numberOfObjects]);
#endif
// Return the number of rows in the section.
return [sectionInfo numberOfObjects];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
return [self basicCellAtIndexPath:indexPath];
}
- (ResultsExtraCellVC *)basicCellAtIndexPath:(NSIndexPath *)indexPath {
ResultsExtraCellVC *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Using a cell identifier will allow your app to reuse cells as they come and go from the screen.
if (cell == nil) {
#ifndef NDEBUG
NSLog(#"%s (line:%d)",__PRETTY_FUNCTION__,__LINE__);
#endif
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ResultsExtraCell" owner:self options:nil];
cell = (ResultsExtraCellVC *)[nib objectAtIndex:0];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(ResultsExtraCellVC *)cell atIndexPath:(NSIndexPath *)indexPath {
#ifndef NDEBUG
NSLog(#"%s (line:%d)",__PRETTY_FUNCTION__,__LINE__);
#endif
Result *result = [_fetchedResultsController objectAtIndexPath:indexPath];
[cell.cellRankNr setText:[NSString stringWithFormat:#"%#",[result endposition]]];
[cell.cellName setText:[NSString stringWithFormat:#"%# %# (%#)",[result pilotprename], [result pilotname], [result carnumber]]];
[cell.cellResult setText:[NSString stringWithFormat:#"%#",NSLocalizedFormatString(#"LapsXnTimeX",[result rlaps],[result rendtime])]];
[cell.cellRace setText:[NSString stringWithFormat:#"%#",NSLocalizedFormatString(#"BestTimeXnAvgTimeX",[result rbesttime], [result rmediumtime])]];
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView respondsToSelector:#selector(setSeparatorInset:)])
{
[tableView setSeparatorInset:UIEdgeInsetsZero];
}
if ([tableView respondsToSelector:#selector(setLayoutMargins:)])
{
[tableView setLayoutMargins:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:#selector(setLayoutMargins:)])
{
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
-(NSString *)getElementName{
NSString *elementName = #"";
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Elements" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init] ;
[request setEntity:entityDescription];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(eventid = %# AND sectionid = %# AND elementid = %# AND categoryid= %#)",eventID, sectionID, elementID, categoryID];
[request setPredicate:predicate]; //added this line later
NSArray *array = [managedObjectContext executeFetchRequest:request error:nil];
if([array count]> 0){
Element *element = [array lastObject];
elementName = [element name];
}
return elementName;
}
-(NSString *)getSectionName{
NSString *sectiontName = #"";
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Sections" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init] ;
[request setEntity:entityDescription];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(eventid = %# AND sectionid = %#)",eventID, sectionID];
[request setPredicate:predicate]; //added this line later
NSArray *array = [managedObjectContext executeFetchRequest:request error:nil];
if([array count]> 0){
Section *section = [array lastObject];
sectiontName = [section name];
}
return sectiontName;
}
-(void)getResults{
// Initialize Fetch Request
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Results"];
// Add Sort Descriptors
//[fetchRequest setSortDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"endposition" ascending:YES]]];
//Predicate
NSPredicate *commentsPredicate = [NSPredicate predicateWithFormat:#"(eventid = %# AND sectionid = %# AND elementid = %#)",eventID, sectionID, elementID];
[fetchRequest setPredicate:commentsPredicate]; //added this line later
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"endposition"
ascending:YES];
NSArray *sortDescriptors = #[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
// Initialize Fetched Results Controller
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
// Configure Fetched Results Controller
[self.fetchedResultsController setDelegate:self];
// Perform Fetch
NSError *error = nil;
[self.fetchedResultsController performFetch:&error];
if (error) {
NSLog(#"Unable to perform fetch.");
NSLog(#"%#, %#", error, error.localizedDescription);
}
}
#pragma mark -
#pragma mark Fetched Results Controller Delegate Methods
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
- (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:(ResultsExtraCellVC *)[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
}
case NSFetchedResultsChangeMove: {
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
}
#end
My View looks like this:
I tried to follow some tutorials as this is the first time i'm doing this with CoreData, previously i always used only UITableViewController.
I followed this: http://code.tutsplus.com/tutorials/core-data-from-scratch-more-nsfetchedresultscontroller--cms-21777
And also checked: CoreData TableView inside UIViewController
But with no success.
I would be great if someone can help me with the problem.
Thanks in advance
Maybe in code line
// Initialize Fetched Results Controller
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
the sectionNameKeyPath is missing? It must be one of the NSSortDescriptor keys.

iOS UITableView with core data crash after delete

I'm working on an iOS app written in Objective-C and I have table view with many records from Core data. When I delete one record the row is deleted from Core data but the app is giving me an error:
-[_PFArray removeObjectAtIndex:]: unrecognized selector sent to instance 0x7fbf5be5e6b0
I have tried many times to change this but it still crashes the app or the table view is not updated after deletion.
This is my header file:
#import <UIKit/UIKit.h>
#include "Notes.h"
#interface ShowClassNote : UIViewController<UITabBarDelegate,UITableViewDataSource>
// get moodle id from segue
#property(strong,nonatomic)NSString*moodeleID;
#property(strong,nonatomic)NSString*moodleName;
#property(strong,nonatomic)NSString*content;
#property (nonatomic, strong) NSMutableArray *fetchedObjects;
#property(strong)NSManagedObjectContext*passThis;
#property(strong,nonatomic)NSString*dataForSend;
#property(strong,nonatomic)NSArray*noteID;
#property(strong,nonatomic)NSArray*noteTitle;
#property(strong,nonatomic)NSArray*insertDates;
#property(strong,nonatomic)NSArray*noteContent;
#property (weak, nonatomic) IBOutlet UILabel *classTitleLable;
#property (weak, nonatomic) IBOutlet UITableView *allNotes;
#end
and this is my implementation file:
#import "ShowClassNote.h"
#import "Subjects.h"
#import "NewClassNote.h"
#import "Notes.h"
#import "AllClassNotesCell.h"
#interface ShowClassNote ()
#end
#implementation ShowClassNote
- (void)viewDidLoad {
[super viewDidLoad];
id delegate =[[UIApplication sharedApplication]delegate];
NSError*error=nil;
NSManagedObjectContext *context = [delegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Notes"
inManagedObjectContext:context];
NSPredicate * predicate =[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"moodleCode=='%#'",self.moodeleID]];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
self.fetchedObjects = [[NSMutableArray alloc]initWithObjects:[context executeFetchRequest:fetchRequest error:&error], nil];
// self.fetchedObjects =(NSMutableArray *) [context executeFetchRequest:fetchRequest error:&error];
// NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
self.noteTitle =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"title"];
self.insertDates =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"insertDate"];
self.noteContent =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"content"];
self.noteID=[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"moodleCode"];
self.classTitleLable.text=self.moodleName;
self.title=self.moodleName;
[self.allNotes reloadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
return 0;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
// This will create a "invisible" footer
return 0.01f;
}
#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 the number of rows in the section.
return [self.fetchedObjects count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * cellIdnt =#"noteCell";
AllClassNotesCell *cell =(AllClassNotesCell *) [tableView dequeueReusableCellWithIdentifier:cellIdnt forIndexPath:indexPath];
// Configure the cell...
// Get current date & time
NSDate *currDate = [self.insertDates objectAtIndex:indexPath.row];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"dd/MM/YY HH:mm"];
NSString* dateToString =[dateFormatter stringFromDate:currDate];
cell.textLabel.text= [self.noteTitle objectAtIndex:indexPath.row] ;
cell.detailTextLabel.text=dateToString;
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 78;
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
id delegate =[[UIApplication sharedApplication]delegate];
// Delete the role object that was swiped
NSUInteger currentSelect = indexPath.row;
NSManagedObjectContext *context = [delegate managedObjectContext];
Notes * roleToDelete= [self.fetchedObjects objectAtIndex:currentSelect];
[context deleteObject:roleToDelete];
// Save the context.
NSError *error;
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
[_fetchedObjects removeObjectAtIndex:currentSelect];
[self.allNotes reloadData];
}
-(void)viewWillAppear:(BOOL)animated{
id delegate =[[UIApplication sharedApplication]delegate];
NSError*error=nil;
NSManagedObjectContext *context = [delegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Notes"
inManagedObjectContext:context];
NSPredicate * predicate =[NSPredicate predicateWithFormat:[NSString stringWithFormat:#"moodleCode=='%#'",self.moodeleID]];
[fetchRequest setPredicate:predicate];
[fetchRequest setEntity:entity];
self.fetchedObjects = (NSMutableArray *)[context executeFetchRequest:fetchRequest error:&error];
self.noteTitle =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"title"];
self.insertDates =[[[NSArray alloc]initWithArray:_fetchedObjects]valueForKey:#"insertDate"];
self.classTitleLable.text=self.moodleName;
self.title=self.moodleName;
[self.allNotes reloadData];
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier]isEqual:#"newNote"]) {
NewClassNote * newNoteView =[segue destinationViewController];
newNoteView.moodleID =self.moodeleID;
newNoteView.newOrOld =YES;
}else if ([[segue identifier]isEqual:#"showNote"])
{
NewClassNote * dvc =[segue destinationViewController];
NSUInteger currentSelect = [self.allNotes indexPathForSelectedRow].row;
NSLog(#"Send is %lu",(unsigned long)currentSelect);
dvc.returnData =[self.fetchedObjects objectAtIndex:currentSelect];
NewClassNote *destViewController = segue.destinationViewController;
destViewController.comingData = [self.noteTitle objectAtIndex:[[self.allNotes indexPathForSelectedRow] row]];
destViewController.insertDate= [self.insertDates objectAtIndex:[[self.allNotes indexPathForSelectedRow] row]];
[self.allNotes reloadData];
}
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
#end
Can you explain to me why I get this error? The total rows after deletion is different than before deletion but I don't know why this errors?
You error goes from here:
self.fetchedObjects = (NSMutableArray *)[context executeFetchRequest:fetchRequest error:&error];
-executeFetchRequest:error: returns NSArray, it's immutable, if you just cast it to NSMutableArray it won't magically change itself. But later you try to
[_fetchedObjects removeObjectAtIndex:currentSelect];
which is sending -removeObjectAtIndex to an NSArray instance.
You can try to solve it like this:
self.fetchedObjects = [[context executeFetchRequest:fetchRequest error:&error] mutableCopy];

Populating Core Data into Table View

I am trying to display data in a custom tableview. Idea is that in ViewController A i populate data into the Core Data entity, in ViewController B I retrieve data from Core Data entity successfully and display it in table view with no problem. Here comes the problem. If I delete data from entity and tableview in ViewController B, go back to ViewController A and add new item to Core Data again, it does not appear in tableview when I go back to ViewController B. But if i close and open the application again, the item appears there again.
So the problem is that the item appear in core data after deleting an item and inserting again, but doesnt appear in tableview. Maybe i have to update tableview somehow, but i tried [self.tableview reloadData]; and it did not help. Code Below. Any Ideas???
ViewController A
#import "ListItem.h"
#import "ViewOrders.h"
#import "MainView.h"
#import "Order_list.h"
#import "AppDelegate.h"
#interface ListItem ()
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSFetchedResultsController *results;
#property (nonatomic, strong) NSMutableArray *namesArray;
#property (nonatomic, strong) NSMutableArray *quantityArray;
#property (nonatomic, strong) NSMutableArray *priceArray;
#property (nonatomic, strong) NSMutableArray *imagesArray;
#end
#implementation ListItem
#synthesize managedObjectContext = _managedObjectContext;
#synthesize results = _results;
#synthesize imageView = _imageView;
#synthesize mainView = _mainView;
#synthesize nameField = _nameField;
#synthesize descField = _descField;
#synthesize priceField = _priceField;
#synthesize quantityField = _quantityField;
#synthesize quantityStepperOutlet = _quantityStepperOutlet;
#synthesize namesArray =_namesArray;
#synthesize quantityArray = _quantityArray;
#synthesize priceArray = _priceArray;
#synthesize imagesArray = _imagesArray;
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = delegate.managedObjectContext;
//self.navigationItem.hidesBackButton = YES;
self.namesArray = [[NSMutableArray alloc] init];
self.quantityArray = [[NSMutableArray alloc] init];
self.priceArray = [[NSMutableArray alloc] init];
self.imagesArray = [[NSMutableArray alloc] init];
UIGraphicsBeginImageContext(self.view.frame.size);
[[UIImage imageNamed:#"bella_italia_crop.png"] drawInRect:self.view.bounds];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
UIGraphicsBeginImageContext(self.mainView.frame.size);
[[UIImage imageNamed:#"bella_italia_crop.png"] drawInRect:self.mainView.bounds];
UIImage *image2 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.mainView.backgroundColor = [UIColor colorWithPatternImage:image2];
self.imageView.image = [UIImage imageNamed:self.thumbnail];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
self.nameField.text = self.name;
self.descField.text = self.description;
self.priceField.text = self.price;
self.descField.backgroundColor = [UIColor clearColor];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"viewAllOrdersSegue"])
{
ViewOrders *vo = segue.destinationViewController;
vo.namesArray = self.namesArray;
vo.quantityArray = self.quantityArray;
vo.priceArray = self.priceArray;
vo.tableNumber = #"1";
vo.imagesArray = self.imagesArray;
}
else if ([segue.identifier isEqualToString:#"unwindToMain"])
{
MainView *mv = segue.destinationViewController;
mv.namesArray = self.namesArray;
mv.quantityArray = self.quantityArray;
mv.priceArray = self.priceArray;
mv.imagesArray = self.imagesArray;
}
}
- (IBAction)quantityStepper:(UIStepper *)sender
{
int stepper = [sender value];
self.quantityField.text = [NSString stringWithFormat:#"%d", stepper];
}
- (IBAction)addOrderAction:(UIButton *)sender
{
NSLog(#"Add order action button pressed");
Order_list *newItem = [NSEntityDescription insertNewObjectForEntityForName:#"Order_list" inManagedObjectContext:self.managedObjectContext];
newItem.title = self.name;
newItem.quantity = #([self.quantityField.text floatValue]);
newItem.price = #([self.priceField.text floatValue]);
newItem.tableNumber = [NSNumber numberWithInt:1];
newItem.thumbnail = self.thumbnail;
newItem.id = [NSNumber numberWithInt:0];
NSError *error;
[self.managedObjectContext save:&error];
UIAlertView *successAlert = [[UIAlertView alloc] initWithTitle:#"Success!" message:#"Your order was successfully added to orders list! Press View Orders to finalize the order or go back to menu and choose something else." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
successAlert.alertViewStyle = UIAlertViewStyleDefault;
[successAlert show];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Order_list" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObjectContext *info in fetchedObjects) {
NSLog(#"Title: %# %#", [info valueForKey:#"title"], [info valueForKey:#"quantity"]);
}
//[self.namesArray addObject:self.name];
//[self.quantityArray addObject:self.quantityField.text];
//int finalPrice = [self.quantityField.text intValue] * [self.price intValue];
//[self.priceArray addObject:[NSString stringWithFormat:#"%d", finalPrice]];
//[self.imagesArray addObject:self.thumbnail];
//NSLog(#"Names: %#, Quantities: %#, Prices: %#", self.namesArray, self.quantityArray, self.priceArray);
}
#end
ViewController B
#import "ViewOrders.h"
#import "AppDelegate.h"
#import "Order_list.h"
#import "ViewOrdersCell.h"
#interface ViewOrders ()
#property (nonatomic, strong) NSMutableData *requestData;
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSFetchedResultsController *results;
#property (nonatomic, strong) NSString* orderState;
#property (nonatomic, strong) UIAlertView *billAlert;
#end
#implementation ViewOrders
#synthesize managedObjectContext = _managedObjectContext;
#synthesize results = _results;
#synthesize confirmOrderButton = _confirmOrderButton;
#synthesize requestData = _requestData;
#synthesize orderState = _orderState;
#synthesize billAlert = _billAlert;
- (void)viewDidLoad
{
[super viewDidLoad];
self.billAlert = [[UIAlertView alloc] initWithTitle:#"Order Confirmed!" message:#"Your order list has been successfully confirmed and is sent to kitchen! Press Request Bill Now or Request Bill Later to Continue (You cannot make any new orders until you request a bill for current one! To trigger this screen again, press and hold on any order in pending orders page. Thanks!)" delegate:self cancelButtonTitle:#"Request Bill Later" otherButtonTitles:#"Request Bill Now", nil];
self.billAlert.tag = 2;
self.billAlert.alertViewStyle = UIAlertViewStyleDefault;
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = delegate.managedObjectContext;
self.namesArray = [[NSMutableArray alloc] init];
self.quantityArray = [[NSMutableArray alloc] init];
self.imagesArray = [[NSMutableArray alloc] init];
self.priceArray = [[NSMutableArray alloc] init];
NSFetchRequest *coreRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Order_list" inManagedObjectContext:self.managedObjectContext];
[coreRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:YES];
[coreRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[coreRequest setFetchBatchSize:20];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:coreRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
self.results = controller;
self.results.delegate = self;
NSError *error;
[self.results performFetch:&error];
NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:coreRequest error:&error];
for (NSManagedObjectContext *info in fetchedObjects)
{
self.orderState = [NSString stringWithFormat:#"%#", [info valueForKey:#"id"]];
[self.namesArray addObject:[info valueForKey:#"title"]];
[self.quantityArray addObject:[info valueForKey:#"quantity"]];
[self.imagesArray addObject:[info valueForKey:#"thumbnail"]];
[self.priceArray addObject:[info valueForKey:#"price"]];
//NSLog(#"List: %#", [info valueForKey:#"title"]);
}
if ([self.orderState isEqualToString:#"1"])
{
self.confirmOrderButton.enabled = false;
}
//self.navigationController.navigationItem.backBarButtonItem.enabled = false;
//self.navigationItem.hidesBackButton = YES;
// 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)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id sectionInfo = [[self.results sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ordersCell" forIndexPath:indexPath];
ViewOrdersCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ordersCell" forIndexPath:indexPath];
cell.title.text = [self.namesArray objectAtIndex:indexPath.row];
cell.thumbnail.image = [UIImage imageNamed:[self.imagesArray objectAtIndex:indexPath.row]];
cell.status.text = #"Waiting to Confirm";
if ([self.orderState isEqualToString:#"0"])
{
cell.status.text = #"Waiting to Confirm";
cell.status.textColor = [UIColor redColor];
}
else
{
cell.status.textColor = [UIColor greenColor];
cell.status.text = #"Confirmed";
}
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(onLongPress:)];
[cell addGestureRecognizer:longPressRecognizer];
//cell.textLabel.text = [self.namesArray objectAtIndex:indexPath.row];
//cell.imageView.image = [UIImage imageNamed:[self.imagesArray objectAtIndex:indexPath.row]];
//cell.backgroundColor = [UIColor clearColor];
return cell;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source
NSManagedObject *managedObject = [self.results objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:managedObject];
[self.managedObjectContext save:nil];
//[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
//[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
if (type == NSFetchedResultsChangeInsert)
{
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
if (type == NSFetchedResultsChangeDelete)
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
if (type == NSFetchedResultsChangeUpdate)
{
}
if (type == NSFetchedResultsChangeMove)
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
if (type == NSFetchedResultsChangeInsert)
{
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
}
if (type == NSFetchedResultsChangeDelete)
{
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
}
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 1 && alertView.tag == 1)
{
NSLog(#"Confirm Pressed");
//////Send Order to the Server//////
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Order_list"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"id=0"];
fetchRequest.predicate = predicate;
NSError *error = nil;
NSArray *array = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObjectContext *info in array)
{
NSNumber *temp = [[NSNumber alloc] initWithInt:1];
[info setValue:temp forKey:#"id"];
}
[self.managedObjectContext save:&error];
[self.tableView reloadData];
self.confirmOrderButton.enabled = false;
[self.billAlert show];
}
else if (buttonIndex == 1 && alertView.tag == 2)
{
self.confirmOrderButton.enabled = true;
UIAlertView *billRequest = [[UIAlertView alloc] initWithTitle:#"Bill Request Successful!" message:#"Your bill has been requested successfully! Waiter will deliver it to you as soon as possible! Thanks for visiting Bella Italia!" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
billRequest.alertViewStyle = UIAlertViewStyleDefault;
billRequest.tag = 3;
[billRequest show];
NSFetchRequest *fetchItems = [[NSFetchRequest alloc] init];
[fetchItems setEntity:[NSEntityDescription entityForName:#"Order_list" inManagedObjectContext:self.managedObjectContext]];
[fetchItems setIncludesPropertyValues:NO]; //only fetch the managedObjectID
NSError *error = nil;
NSArray *array = [self.managedObjectContext executeFetchRequest:fetchItems error:&error];
[self.results performFetch:&error];
//error handling goes here
for (NSManagedObject *item in array)
{
[self.managedObjectContext deleteObject:item];
}
NSError *saveError = nil;
[self.managedObjectContext save:&saveError];
}
else if (buttonIndex == 0 && alertView.tag == 2)
{
}
else if (buttonIndex == 0 && alertView.tag == 3)
{
[self.navigationController popToRootViewControllerAnimated:UITableViewRowAnimationFade];
}
}
- (IBAction)confirmOrder:(UIBarButtonItem *)sender
{
NSLog(#"Confirm Order");
UIAlertView *confOrder = [[UIAlertView alloc] initWithTitle:#"Confirm Order!" message:#"This will send your order to process. Once this is done, no more changes are available. Are you sure you want to confirm your order?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Confirm", nil];
confOrder.alertViewStyle = UIAlertViewStyleDefault;
confOrder.tag = 1;
[confOrder show];
}
-(void)onLongPress:(UILongPressGestureRecognizer*)pGesture
{
NSLog(#"Long Press");
[self.billAlert show];
}
#end
EDIT
Forgot to mention that i am using Custom Cell. Maybe that affects the situation somehow?
I tried to NSLog the variables which store the data that supposed to appear in tableview. All the data is beeing passed, but it does not appear in tableview. Logically [self.tableView reloadData in viewWillAppear should do the trick, but it does not........
I have a similar setup in one my apps and I add an observer to the ViewController with the table that wants updating;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reload) name:#"UpdatedCoreData" object:nil];
I clear any arrays or dictionaries I use in the reload method and call (inside my async queue);
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
Then when I finish updating the core data in my other VC I call it;
[[NSNotificationCenter defaultCenter] postNotificationName:#"UpdatedCoreData" object: nil];
And that works perfectly fine for me, I don't know if that will help you at all.
EDIT:
Along the lines of my reload method;
- (void)reload {
// Do any potential clean up if neccesary
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Fetch core data & populate dictionaries/arrays
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
});
}

whats wrong with this code? not populating table from core data!! iPad

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();
}

Why is NSFetchedResultsController assigning fetched objects to multiple UITableView sections?

In another question of mine concerning the addition of an insert row in a UITableView backed by Core Data, I mentioned that my NSFetchedResultsController is assigning each object it fetches to a separate section in my UITableView. I assumed this was merely the default behavior, but Marcus S. Zarra said there might be something wrong with my configuration of the controller or my datasource delegate methods. I admit, my code feels a bit like Frankenstein with parts pulled from the Apple docs and numerous tutorials. This is my first program and my first time using Core Data, so please be gentle ;)
My table view controller's header is as follows:
#import <UIKit/UIKit.h>
#import "RubricAppDelegate.h"
#interface ClassList : UITableViewController {
NSMutableArray *classList;
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
}
#property(nonatomic,retain) NSMutableArray *classList;
#property(nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property(nonatomic, retain) NSManagedObjectContext *managedObjectContext;
- (IBAction) grade:(id)sender;
#end
My implementation file includes a bunch of dummy test data. I included that in case I am using incorrect methods for instantiating the Core Data objects. Basically, I want to know if my NSFetchedResultsController should not be returning my objects (in this case, instances of myClass) into separate sections. If so, what am I doing to create that problem?
The ultimate goal at the moment is for me to be able to add an insert cell at the top of my table (I know that putting it at the bottom is "standard," but I like how it looks in the apps that do it the other way around). You will notice my -tableView:editingStyleForRowAtIndexPath: sets the cell style of section 0 to insert, but of course I need to figure out how to start the listing of myClass.classTitle at cell 1 instead of cell 0 (which is why I want to determine if having each object assigned to its own section is normal).
Here is my implementation file:
#import "ClassList.h"
#import "ClassRoster.h"
#import "RubricAppDelegate.h"
#import "Student.h"
#import "myClass.h"
#implementation ClassList
#synthesize classList;
#synthesize fetchedResultsController;
#synthesize managedObjectContext;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.editing = YES;
RubricAppDelegate *appDelegate = (RubricAppDelegate *)[[UIApplication sharedApplication] delegate];
managedObjectContext = [appDelegate managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"myClass" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entity];
//test data
myClass *newClass = (myClass *) [NSEntityDescription insertNewObjectForEntityForName:#"myClass" inManagedObjectContext:managedObjectContext];
newClass.classTitle = #"UFDN 1000";
NSNumber *ID = [NSNumber numberWithInt:1];
newClass.classID = ID;
Student *newStudent = (Student *) [NSEntityDescription insertNewObjectForEntityForName:#"Student" inManagedObjectContext:managedObjectContext];
newStudent.classID = ID;
newStudent.studentName = #"Andy Albert";
newStudent.studentUsername = #"albera";
[newClass addStudentsObject:newStudent];
newStudent.classID = ID;
newStudent.studentName = #"Bob Dole";
newStudent.studentUsername = #"doleb";
[newClass addStudentsObject:newStudent];
newStudent.classID = ID;
newStudent.studentName = #"Chris Hanson";
newStudent.studentUsername = #"hansoc";
[newClass addStudentsObject:newStudent];
myClass *newClass2 = (myClass *) [NSEntityDescription insertNewObjectForEntityForName:#"myClass" inManagedObjectContext:managedObjectContext];
newClass2.classTitle = #"UFDN 3100";
ID = [NSNumber numberWithInt:2];
newClass2.classID = ID;
newStudent.classID = ID;
newStudent.studentName = #"Danny Boy";
newStudent.studentUsername = #"boyd";
[newClass2 addStudentsObject:newStudent];
newStudent.classID = ID;
newStudent.studentName = #"James Matthews";
newStudent.studentUsername = #"matthj";
[newClass2 addStudentsObject:newStudent];
newStudent.classID = ID;
newStudent.studentName = #"Aaron Todds";
newStudent.studentUsername = #"toddsa";
[newClass2 addStudentsObject:newStudent];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"classID" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
NSError *error;
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"classTitle" cacheName:nil];
[fetchedResultsController performFetch:&error];
UIBarButtonItem *gradeButton = [[UIBarButtonItem alloc]
initWithTitle:#"Grade"
style:UIBarButtonItemStylePlain
target:self
action:#selector(grade:)];
self.navigationItem.rightBarButtonItem = gradeButton;
[gradeButton release];
}
- (IBAction) grade:(id)sender {
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"Number of sections = %d", [[fetchedResultsController sections] count]);
return ([[fetchedResultsController sections] count]);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
id <NSFetchedResultsSectionInfo> myClass = [[fetchedResultsController sections] objectAtIndex:section];
NSLog(#"Number of classes = %d", [myClass numberOfObjects]);
return [myClass 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];
myClass *theClass = [fetchedResultsController objectAtIndexPath:indexPath];
NSLog(#"Class name is: %#", theClass.classTitle);
cell.textLabel.text = theClass.classTitle;
}
return cell;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
return UITableViewCellEditingStyleInsert;
}
else return UITableViewCellEditingStyleDelete;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
myClass *result = (myClass *)[fetchedResultsController objectAtIndexPath:indexPath];
[managedObjectContext deleteObject:result];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
}
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc {
[classList release];
[super dealloc];
}
#end
My RubricAppDelegate is essentially identical to the Apple documentation for setting up Core Data NSManagedObjectContext, NSPersistentStoreCoordinator, etc. However, if you think there might be a problem in there, just let me know and I'll post it.
Edit: I forgot to mention two reasons I know each object is being assigned to a different section.
1) NSLog(#"Number of sections = %d", [[fetchedResultsController sections] count]); inside of -numberOfSectionsInTableView: returns the number of myClass objects I have.
2) If I set -numberOfSectionsInTableView: to return 1, my table only displays one object and cuts the rest out.
You have sections because you tell the fetched results controller to create them by passing a non-Nil value for sectionNameKeyPath: when you initialize the FRC.
Change:
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:#"classTitle" cacheName:nil];
...to:
fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil cacheName:nil];
... and the sections will go away. Otherwise, the FRC will create one section for each value of the classTitle attribute in the store. If each myClass instance has a different value for classTitle each instance will have its own section in the tableview.

Resources