iOS UITableView with core data crash after delete - ios

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];

Related

Refreshing table view using core data

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!

Open edit view controller from table view using core data

In my iOS app I am using Core Data to show data on a table view. On the same view I have included an add button, which opens a new view controller where I can add a new record.
From this view I return to the table view and the new added record is shown correctly. Now, what I want to do is to select a row on the table view and open a new view controller to edit the fields of the record. The edit view controller name is EditViewController. Here is my table view controller source, so yo can please explain me the method to implement to pass the selected row record to the edit view controller, so I can later edit and save the information.
I have seen some examples for that question regarding the didSelectedRowAtIndexPath method, but all based on a storyboard, which I am not using in my project.
#import "RootViewController.h"
#import "AddToDoViewController.h"
#interface RootViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
#end
#implementation RootViewController
#synthesize fetchedResultsController, managedObjectContext,AddToDoButton;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setTitle:#"Today"];
[[self navigationItem] setRightBarButtonItem:[self editButtonItem]];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
- (void) viewWillAppear:(BOOL)animated{
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
[[cell textLabel] setText:[[managedObject valueForKey:#"thingName"] description]];
[[cell detailTextLabel] setText:[[managedObject valueForKey:#"thingDescription"] description]];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.textLabel.textColor = [UIColor blueColor];
cell.textLabel.font = [UIFont fontWithName:#"Noteworthy" size:16.0f];
cell.detailTextLabel.font = [UIFont fontWithName:#"Noteworthy" size:14.0f];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:#"Cell"] autorelease];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toIndexPath:(NSIndexPath *)destinationIndexPath;
{
NSMutableArray *things = [[fetchedResultsController fetchedObjects] mutableCopy];
// Grab the item we're moving.
NSManagedObject *thing = [[self fetchedResultsController] objectAtIndexPath:sourceIndexPath];
// Remove the object we're moving from the array.
[things removeObject:thing];
// Now re-insert it at the destination.
[things insertObject:thing atIndex:[destinationIndexPath row]];
// All of the objects are now in their correct order. Update each
// object's displayOrder field by iterating through the array.
int i = 0;
for (NSManagedObject *mo in things)
{
[mo setValue:[NSNumber numberWithInt:i++] forKey:#"displayOrder"];
}
[things release], things = nil;
[managedObjectContext save:nil];
}
#pragma mark -
#pragma mark Fetched results controller
- (IBAction)AddToDoAction:(id)sender {
AddToDoViewController *viewController = [[AddToDoViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController) return fetchedResultsController;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"FavoriteThing"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"displayOrder"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc]
initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil cacheName:#"ThingsCache"];
aFetchedResultsController.delegate = self;
[self setFetchedResultsController:aFetchedResultsController];
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
- (void)dealloc {
[fetchedResultsController release];
[managedObjectContext release];
[super dealloc];
}
#end
Hi again. I have done following after the answer from #flexaddicted:
I have add following code to my EditToDoViewController.h file at the interface block:
NSManagedObject *selectedObject;
And also following declaration:
#property (nonatomic, retain) NSManagedObject *selectedObject;
And in my EditToDoViewController.m file i have added following code:
#synthesize selectedObject;
The didSelectRowAtIndexPath method changed to:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
EditToDoViewController *detailViewController = [[EditToDoViewController alloc] initWithNibName:#"EditToDoViewController" bundle:nil];
NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
EditToDoViewController.selectedObject = selectedObject;
}
But at this point I am receiving this error message:
Property 'selectedObject' not found on object of type 'EditToDoViewController'
I think I have well declared the property 'selectedObject', I don't understand the error....
Thank you
Step 1
Implement the correct delegate method for UITableView, that is UITableViewDelegate.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// do something here (see Step 2 and 3)
}
Step 2
Retrieve the correct item.
NSManagedObject *mo = [yourResultsController objectAtIndexPath:indexPath];
Step 3
Present a modal controller passing it data. An alternative is to wrap the controller you are using in a UINavigationController and do a push of a new controller. Example.
YourAdditionalViewController *ac = [[YourAdditionalViewController alloc] init];
ac.setMo = mo; // as a property or passed to a custom init method of YourAdditionalController
[self presentViewController:ac animated:YES completion: nil];
So to recap.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *mo = [yourResultsController objectAtIndexPath:indexPath];
YourAdditionalViewController *ac = [[YourAdditionalViewController alloc] init];
ac.setMo = mo; // as a property or passed to a custom init method of YourAdditionalController
[self presentViewController:ac animated:YES completion: nil];
}
Let me know if I need to improve my answer.
P.S. Check the code since I've written without Xcode support.

My app doesn't react at the didSelectRowAtIndex: method

i don't know what I am doing wrong, but my app is not working as expected. I have a tableview controller, and today I have included the didSelectRowAtIndexPath: method to open a detail view from the selected row, but when tapping on the row nothing happens. Here is my code, maybe you find the reason why it is not firing the detail view.
#import "RootViewController.h"
#import "AddToDoViewController.h"
#import "EditToDoViewController.h"
#interface RootViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
#end
#implementation RootViewController
#synthesize fetchedResultsController, managedObjectContext,AddToDoButton;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setTitle:#"Today"];
[[self navigationItem] setRightBarButtonItem:[self editButtonItem]];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
- (void) viewWillAppear:(BOOL)animated{
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
[[cell textLabel] setText:[[managedObject valueForKey:#"thingName"] description]];
[[cell detailTextLabel] setText:[[managedObject valueForKey:#"thingDescription"] description]];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.textLabel.textColor = [UIColor blueColor];
cell.textLabel.font = [UIFont fontWithName:#"Noteworthy" size:17.0f];
cell.detailTextLabel.font = [UIFont fontWithName:#"Noteworthy" size:15.0f];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
EditToDoViewController *detailViewController = [[EditToDoViewController alloc] initWithNibName:#"EditToDoViewController" bundle:nil];
NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
detailViewController.selectedObject = selectedObject;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:#"Cell"] autorelease];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toIndexPath:(NSIndexPath *)destinationIndexPath;
{
NSMutableArray *things = [[fetchedResultsController fetchedObjects] mutableCopy];
// Grab the item we're moving.
NSManagedObject *thing = [[self fetchedResultsController] objectAtIndexPath:sourceIndexPath];
// Remove the object we're moving from the array.
[things removeObject:thing];
// Now re-insert it at the destination.
[things insertObject:thing atIndex:[destinationIndexPath row]];
// All of the objects are now in their correct order. Update each
// object's displayOrder field by iterating through the array.
int i = 0;
for (NSManagedObject *mo in things)
{
[mo setValue:[NSNumber numberWithInt:i++] forKey:#"displayOrder"];
}
[things release], things = nil;
[managedObjectContext save:nil];
}
#pragma mark -
#pragma mark Fetched results controller
- (IBAction)AddToDoAction:(id)sender {
AddToDoViewController *viewController = [[AddToDoViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController) return fetchedResultsController;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"FavoriteThing"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"displayOrder"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc]
initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil cacheName:#"ThingsCache"];
aFetchedResultsController.delegate = self;
[self setFetchedResultsController:aFetchedResultsController];
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
- (void)dealloc {
[fetchedResultsController release];
[managedObjectContext release];
[super dealloc];
}
#end
Here is my header file code:
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate> {
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
}
#property (retain, nonatomic) IBOutlet UIBarButtonItem *AddToDoButton;
- (IBAction)AddToDoAction:(id)sender;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#end
EditToDoViewController *detailViewController = [[EditToDoViewController alloc] initWithNibName:#"EditToDoViewController" bundle:nil];
NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
detailViewController.selectedObject = selectedObject;
[self.navigationController pushViewController:detailViewController animated:YES];
you forgot to push your view controller.

Reloading table view from another view

In my iOS app I need a tableview to be updated from another view. I have tried using NSNotifications but no success.The first view contains a tableview populated from core data using a fetch request. This view has also a Add button which opens a view to add objects to the core data entity.This second view has several text fields, a save button and a back button that opens the first view again, but the rows are not updated.
THis is the code from the first view controller:
#import "RootViewController.h"
#import "AddToDoViewController.h"
#interface RootViewController ()
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
#end
#implementation RootViewController
#synthesize fetchedResultsController, managedObjectContext,AddToDoButton;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setTitle:#"Today"];
[[self navigationItem] setRightBarButtonItem:[self editButtonItem]];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
- (void) viewWillAppear:(BOOL)animated{
[self.tableView reloadData];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
[[cell textLabel] setText:[[managedObject valueForKey:#"thingName"] description]];
[[cell detailTextLabel] setText:[[managedObject valueForKey:#"thingDescription"] description]];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.textLabel.textColor = [UIColor blueColor];
cell.textLabel.font = [UIFont fontWithName:#"Noteworthy" size:16.0f];
cell.detailTextLabel.font = [UIFont fontWithName:#"Noteworthy" size:14.0f];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:#"Cell"] autorelease];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toIndexPath:(NSIndexPath *)destinationIndexPath;
{
NSMutableArray *things = [[fetchedResultsController fetchedObjects] mutableCopy];
// Grab the item we're moving.
NSManagedObject *thing = [[self fetchedResultsController] objectAtIndexPath:sourceIndexPath];
// Remove the object we're moving from the array.
[things removeObject:thing];
// Now re-insert it at the destination.
[things insertObject:thing atIndex:[destinationIndexPath row]];
// All of the objects are now in their correct order. Update each
// object's displayOrder field by iterating through the array.
int i = 0;
for (NSManagedObject *mo in things)
{
[mo setValue:[NSNumber numberWithInt:i++] forKey:#"displayOrder"];
}
[things release], things = nil;
[managedObjectContext save:nil];
}
#pragma mark -
#pragma mark Fetched results controller
- (IBAction)AddToDoAction:(id)sender {
AddToDoViewController *viewController = [[AddToDoViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController) return fetchedResultsController;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:#"FavoriteThing"
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor =
[[NSSortDescriptor alloc] initWithKey:#"displayOrder"
ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc]
initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil cacheName:#"ThingsCache"];
aFetchedResultsController.delegate = self;
[self setFetchedResultsController:aFetchedResultsController];
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
- (void)dealloc {
[fetchedResultsController release];
[managedObjectContext release];
[super dealloc];
}
#end
And this is the code from the second view controller
#import "AddToDoViewController.h"
#import "FavoriteThing.h"
#import "AppDelegate.h"
#import "RootViewController.h"
#interface AddToDoViewController ()
#end
#implementation AddToDoViewController
#synthesize ToDoDescriptionTextField,ToDoTextField,fetchedResultsController;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[ToDoTextField becomeFirstResponder];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)BackButtonAction:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)SaveButtonAction:(id)sender {
AppDelegate* appDelegate = [AppDelegate sharedAppDelegate];
NSManagedObjectContext* context = appDelegate.managedObjectContext;
NSManagedObject *favoriteThing = [NSEntityDescription insertNewObjectForEntityForName:#"FavoriteThing" inManagedObjectContext:context];
[favoriteThing setValue:#"ToDo 000250" forKey:#"thingName"];
[favoriteThing setValue:#"It sold out in eight days this year, you know?" forKey:#"thingDescription"];
[favoriteThing setValue:[NSNumber numberWithInt:0] forKey:#"displayOrder"];
NSError *error;
if(! [context save:&error])
{
NSLog(#"Whoopw,couldn't save:%#", [error localizedDescription]);
}
}
#end
Reload Your tableview in viewWillAppear.
-(void)viewWillAppear:(BOOL)animated
{
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[self.tableView reloadData];
}
Since you are using NSFetchedResultsController you should use it's delegate to update your table.
Otherwise you do not need to use a NSFetchedResultsController. For information on implementing NSFetchedResultsController delegate please see this link.
Declare this custom delegate in your addVC
#protocol AddViewControllerDelegate <NSObject>
-(void)AddPhotoViewController:(AddViewController *)addViewController store:(NSString *) data;
#end
and declare custom delegate as property variable in addVC
#property(strong, nonatomic) id <AddViewControllerDelegate> delegate;
In mainVC do this
while push addVC like this
AddPhotoViewController* addVC = [[AddPhotoViewController alloc]init];
addVC.delegate = self;
[self.navigationController pushViewController:addVC animated:YES];
-(void)AddPhotoViewController:(AddPhotoViewController *)addViewController store:(NSString *)data
{
[table_array addObject:data];
[self.tableView reloadData];
}

Display NSSet data from Core Data

I am adding values into 2 entities within my core data model and the problem I am facing is trying to properly retrieve the NSSet and target the associated strings when accessing the detail view.I would simply like to display the results in a uitableview. I believe the values are being correctly added along with the relationships to the entities as I previously got help off the forum for it as viewable here. I am trying to recall the associated RoutinesDetail data on the detail view.
I know the seague is working correctly as I am able to set the title based on the selectedRow, so it is passing the data between view controllers. I can recall 'Routines' data using Ex.routinename
Using the following to debug and try to allocate the NSSet as I read a way to display it was to use allObjects but this didn't work:
NSArray *test= [Ex.routinedet allObjects];
NSSortDescriptor *desc = [[NSSortDescriptor alloc] initWithKey:#"image"
ascending:YES];
test = [test sortedArrayUsingDescriptors:[NSArray arrayWithObject:desc]];
NSLog(#"Image *** %#",test);
This produces the following report which makes me question whether I am doing it right?
"<RoutinesDetails: 0x7453d80> (entity: RoutinesDetails; id: 0x74531f0
<x-coredata://C075DDEC-169D-46EC-A4B7-972A04FCED70/RoutinesDetails/p1>
; data: <fault>)"
)
So basically I am looking at how to retrieve RoutinesDetails. Any suggestions would be greatly appreciated.
**
In case it is needed here is the associated code
**
routines.h - NSManagedObject
#class RoutinesDetails;
#interface Routines : NSManagedObject
#property (nonatomic, retain) id routinename;
#property (nonatomic, retain) NSSet *routinedet;
#end
#interface Routines (CoreDataGeneratedAccessors)
- (void)addRoutinedetObject:(RoutinesDetails *)value;
- (void)removeRoutinedetObject:(RoutinesDetails *)value;
- (void)addRoutinedet:(NSSet *)values;
- (void)removeRoutinedet:(NSSet *)values;
#end
RoutinesDetails.h - NSManagedObject
#class Routines;
#interface RoutinesDetails : NSManagedObject
#property (nonatomic, retain) NSString * image;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) Routines *routineinfo;
#end
FBCDRoutineDetailViewController(sorry if its too much code)
#import "FBCDRoutineDetailViewController.h"
#import "FBCDRoutineViewController.h"
#import "Routines.h"
#import "RoutinesDetails.h"
#interface FBCDRoutineDetailViewController ()
#end
#implementation FBCDRoutineDetailViewController
#synthesize managedObjectContext;
#synthesize fetchedResultsController = _fetchedResultsController;
#synthesize Ex;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"RoutinesDetails" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc]
initWithKey:#"name" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext sectionNameKeyPath:nil
cacheName: nil];
self.fetchedResultsController = theFetchedResultsController;
_fetchedResultsController.delegate = self;
return _fetchedResultsController;
}
- (void)viewDidLoad
{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
[super viewDidLoad];
// Do any additional setup after loading the view.
NSArray *test= [Ex.routinedet allObjects];
NSSortDescriptor *desc = [[NSSortDescriptor alloc] initWithKey:#"image"
ascending:YES];
test = [test sortedArrayUsingDescriptors:[NSArray arrayWithObject:desc]];
NSLog(#"Image *** %#",test);
self.title = Ex.routinename;
NSLog(#"Image *** %#",Ex.routinename);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view delegate
- (IBAction)save:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{ }
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { }
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id sectionInfo =
[[_fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
//RoutinesDetails *info = [_fetchedResultsController objectAtIndexPath:indexPath];
NSArray *test= [Ex.routinedet allObjects];
NSSortDescriptor *desc = [[NSSortDescriptor alloc] initWithKey:#"image"
ascending:YES];
test = [test sortedArrayUsingDescriptors:[NSArray arrayWithObject:desc]];
//cell.textLabel.text = info.image;
cell.textLabel.text = [[test objectAtIndex:indexPath.row] name];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"routineCell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Set up the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Any suggestions would be greatly appreciated.
I think you are seeing what you want. I assume EX is an exercise, a routine, and that you are trying to print out the associated details. Your debugging statement displays one RoutinesDetails
(entity: RoutinesDetails; id: 0x74531f0 ; data: )" )
Try this to help you visualize
for (RoutinesDetails *detail in Ex.routinedet) {
NSLog(#"image: %#, name: %#, routineName: %#",detail.image, detail.name, detail.routineinfo.routinename);
}

Resources