I am getting the following error:
Unresolved error (null), (null)
Any ideas what this could be related to - I am trying to allow the users a swipe option to delete an item from Core Data... Adding & Displaying the data works - however deleting shows the error...
#implementation List
#synthesize eventsArray;
#synthesize managedObjectContext, fetchedResultsController, List;
...
- (void)viewDidLoad
{
[super viewDidLoad];
if (managedObjectContext == nil)
{
managedObjectContext = [(ApplicationAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(editAction)];
self.navigationItem.leftBarButtonItem = editButton;
[editButton release];
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target: self action:#selector(addAction)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.fetchedResultsController.delegate = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
List = [[NSMutableArray alloc] init];
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Items" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects)
{
[List insertObject:[info valueForKey:#"Name"] atIndex:0];
}
[fetchRequest release];
[self.tableView reloadData];
}
...
#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 [List count];
}
- (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];
}
// Get and display the values for the keys; the key is the attribute name from the entity
cell.textLabel.text = [List objectAtIndex:indexPath.row];
// Add a standard disclosure for drill-down navigation
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
[context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
// Save the context.
NSError *error = nil;
if (![context save:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
} }
}
- (void)dealloc
{
[fetchedResultsController release];
[List release];
[super dealloc];
}
#end
Firstly, you have the name of your view controller implementation as 'List' but also seem to have an ivar named List. Check the name of the view controller class as this should be the name after the #implementation declarative.
Also, if the name of your NSArray is List then the usual coding convention is to keep ivars starting with lower case. Keeping class names with upper case and ivars with lower case should help avoid confusion in the future.
Related
I am able to navigate to the table view But my table is not showing any data neither it is showing error, I want to save my data to core data and want to display it to the table view but it is not showing anything.
Here is some code snippet of my application -
On clicking of save button -
- (IBAction)saveDataButton:(id)sender {
NSManagedObjectContext *context = [self manageobjectcontext];
// NSManagedObject *newemployee = [NSEntityDescription insertNewObjectForEntityForName:#"Employee" inManagedObjectContext:context];
if (self.employeeDB) {
[self.employeeDB setValue:self.empName.text forKey:#"name"];
[self.employeeDB setValue:self.empEmail.text forKey:#"email"];
[self.employeeDB setValue:self.empDesignation.text forKey:#"designation"];
// [self.employeeDB setValue:self.uploadImage.imageView forKey:#"image"];
}
else{
NSManagedObject *newemployee = [NSEntityDescription insertNewObjectForEntityForName:#"Employee" inManagedObjectContext:context];
[newemployee setValue:self.empName.text forKey:#"name"];
[newemployee setValue:self.empEmail.text forKey:#"email"];
[newemployee setValue:self.empDesignation.text forKey:#"designation"];
}
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Cant save %# %#",error,[error localizedDescription]);
}
UIViewController *objOfView = [[UIViewController alloc]initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:objOfView animated:YES];
}
Here is my second view controller code for displaying data into the table view -
-(NSManagedObjectContext *)manageobjectcontext{
NSManagedObjectContext *context = nil;
_delegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
if ([_delegate respondsToSelector:#selector(persistentContainer)]) {
context = _delegate.persistentContainer.viewContext;
}
return context;
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSManagedObjectContext *manageobjectcontext = [self manageobjectcontext];
NSFetchRequest *fetchrequest = [[NSFetchRequest alloc]initWithEntityName:#"Employee"];
self.employeeArray = [[manageobjectcontext executeFetchRequest:fetchrequest error:nil]mutableCopy];
[self.emplyoyeeTableView reloadData];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.employeeArray.count;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
NSManagedObject *emp = [self.employeeArray objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#",[emp valueForKey:#"name"]]];
[cell.detailTextLabel setText:[NSString stringWithFormat:#"%#",[emp valueForKey:#"email"]]];
[cell.detailTextLabel setText:[NSString stringWithFormat:#"%#",[emp valueForKey:#"designation"]]];
// [cell.imageView setImage:[emp valueForKey:#"image"]];
return cell;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
`- (void)viewDidLoad
{
[super viewDidLoad];
self.employeeArray=[[NSMutableArray alloc] init]; //do this step
// Do any additional setup after loading the view.
}`
Seems like you are not implemeting and setting your tableview delegates properly. Try
#interface YourClass ()<UITableViewDelegate, UITableViewDataSource> {
- (void)viewDidLoad {
[super viewDidLoad];
self.employeeArray=[[NSMutableArray alloc] init]; //do this
tableView.dataSource = self
tableview.delegate = self
// Do any additional setup after loading the view.
}
}
So this is my first time working with core data, and so far it hasn't been the best experience. My application so far consists of two UITableView controllers and a single ViewController. The app simply asks the user to enter the name of a list on UIAlert and it saves to core data, and the name of the list is put into the first tableview. Then the user clicks on the name of the list and it pushes them to the contents on the list, which is empty because it hasn't been populated yet. Then the user populates the TableView, so it pushes to the single view controller where you would enter all the info and hit save. My problem is it doesn't save when I hit save, it goes back to the last UITableView Controller and nothing is there. Thats my first problem, my second is I would like to pass the data between views so when the user clicks on a list it pushes to the second UITableView Controller and says the name of the list at the top. I'm getting really confused with all the core data stuff and relationships so if someone could help me out I would appreciate it. I'll include my code and data model.
Data Model
First Views .m (view that lists all the lists)
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate respondsToSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the lists from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"List"];
self.lists = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.lists.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *list = [self.lists objectAtIndex:indexPath.row];
[cell.textLabel setText:[list valueForKey:#"name"]];
return cell;
}
-(IBAction)add:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Add List" message:#"Create a New Wish List" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Save", nil];
[alert setAlertViewStyle:UIAlertViewStylePlainTextInput];
[alert setTag:2];
[alert show];
alert.delegate = self;
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != 0 && alertView.tag == 2) {
UITextField *tf = [alertView textFieldAtIndex:0];
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *newList = [NSEntityDescription insertNewObjectForEntityForName:#"List" inManagedObjectContext:context];
[newList setValue:tf.text forKey:#"name"];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"List"];
self.lists = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (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
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.lists objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove list from table view
[self.lists removeObjectAtIndex:indexPath.row];
[self.items removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
#end
Second view's .m (view that displays all items in list)
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate respondsToSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the lists from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Item"];
self.lists = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *item = [self.items objectAtIndex:indexPath.row];
[cell.textLabel setText:[item valueForKey:#"list"]];
return cell;
}
- (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
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.items objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.items removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
#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];
*/
}
#pragma mark - Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowDetails"]) {
NSManagedObject *selectedItem = [self.items objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
AddViewController *destViewController = segue.destinationViewController;
destViewController.items = selectedItem;
}
}
#end
And last view (view that adds items to list)
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate respondsToSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *newItem = [NSEntityDescription insertNewObjectForEntityForName:#"Item" inManagedObjectContext:context];
[newItem setValue:self.lists forKey:#"list"];
[newItem setValue:self.lists forKey:#"list"];
[newItem setValue:self.lists forKey:#"list"];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
In my model view that allows me to create a new item:
[newItem setValue:self.name.text forKey:#"itemName"];
[newItem setValue:self.price.text forKey:#"price"];
[newItem setValue:self.desc.text forKey:#"description"];
Error:
self=(AddViewController *)0x8d22e90
newItem=(Item_Item_ *)0x8a636b0
It's not completely clear to me how all of these controllers are wired together. A handful of suggestions to consider when working with Core Data:
There are a variety of ways to deal with the managed object context that you'll use on the main queue. Many use dependency injection to pass the context along the controller hierarchy, rather than ask the application delegate for it in each controller.
You can simplify your life considerably by subclassing NSManagedObject so that you don't have to use KVC to access properties on the entities. Xcode can do it for you; but mogenerator offers much more.
NSFetchedResultsController can sometimes help simplify working with Core Data and table views; but it also adds its own set of quirks.
That said, I can't tell whether any of this is related to your problems or would necessarily help; so I put together a sample app that roughly mirrors part of what you're trying to do. (I think...) It leaves out a lot of the logic for collecting data from your user etc. but you can look at how you might consider putting together a Core Data app such as this.
See this repository on github.
So this is my first time working with core data, and so far it hasn't been the best experience. My application so far consists of two UITableView controllers and a single ViewController. The app simply asks the user to enter the name of a list on UIAlert and it saves to core data, and the name of the list is put into the first tableview. So far so good. Then the user clicks on the name of the list and it pushes them to the contents on the list, which is empty because it hasn't been populated yet. So my problem is when I go to populate it my app just crashes. I don't even get to the the ViewController. I'm really lost I'll put the necessary code here if there's any more let me know. Thanks!
Error argv char ** 0xbfffeda8 0xbfffeda8
Data Model:
The .m To Add Items to the list:
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *newItem = [NSEntityDescription insertNewObjectForEntityForName:#"Item" inManagedObjectContext:context];
[newItem setValue:self.name.text forKey:#"itemName"];
[newItem setValue:self.price.text forKey:#"price"];
[newItem setValue:self.desc.text forKey:#"description"];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
The .m to show all the items in a list:
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the lists from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Item"];
self.lists = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
self.items = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *item = [self.items objectAtIndex:indexPath.row];
[cell.textLabel setText:[item valueForKey:#"itemName"]];
return cell;
}
- (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
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.items objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.items removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
#pragma mark - Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowDetails"]) {
NSManagedObject *selectedItem = [self.items objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
AddViewController *destViewController = segue.destinationViewController;
destViewController.items = selectedItem;
}
}
#end
And the .m displaying all the lists:
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the lists from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"List"];
self.lists = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
self.items = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.lists.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *list = [self.lists objectAtIndex:indexPath.row];
[cell.textLabel setText:[list valueForKey:#"name"]];
return cell;
}
-(IBAction)add:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Add List" message:#"Create a New Wish List" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Save", nil];
[alert setAlertViewStyle:UIAlertViewStylePlainTextInput];
[alert setTag:2];
[alert show];
alert.delegate = self;
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != 0 && alertView.tag == 2) {
UITextField *tf = [alertView textFieldAtIndex:0];
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *newList = [NSEntityDescription insertNewObjectForEntityForName:#"List" inManagedObjectContext:context];
[newList setValue:tf.text forKey:#"name"];
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"List"];
self.lists = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
self.items = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (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
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.lists objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove list from table view
[self.lists removeObjectAtIndex:indexPath.row];
[self.items removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
#end
You should consider using an NSFetchedResultsController to make your life easier, and your app more efficient.
This is incorrect:
self.lists = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
self.items = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
because these sets should contain different types of entity instance. But, you don't actually need self.items. The model contains a relationship between List and Item and you should just get the items for a specified list using that relationship (or a fetch request using the relationship) when you need it. And remove self.items, it's just confusing you. In the list view controller you don't need the items anyway.
When you push to show the items, you should be getting the selected List and passing that. So where you have destViewController.items = selectedItem; you should have something like destViewController.list = selectedList;, and then the item controller uses the relationship again to display the appropriate items.
And, when you add a new item, you have to associated it with self.list:
[newItem setValue:self.list forKey:#"list"];
You should also use managed object subclasses, and the best way to manage them is by using mogenerator.
Aside: Where you have if ([delegate performSelector: it should be if ([delegate respondsToSelector:, and probably log if you don't get a context back...
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.
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];
}