Update core data object on UITableViewCell touch - ios

I have a simple todo app, where a user can touch a cell to check/uncheck a task. But I am not sure how to update Core Data setting the boolean value of completed to yes.
Here is my code:
//
// PakkelisteViewController.m
// Sommerleir
//
// Created by Ronny-André Bendiksen on 08.05.14.
// Copyright (c) 2014 Arbeidernes Ungdomsfylking. All rights reserved.
//
#import "PakkelisteViewController.h"
#import "AUFToDoItem.h"
#import "TodoCell.h"
#interface PakkelisteViewController ()
#property NSMutableArray *toDoItems;
-(IBAction)addNewToDoItem;
#end
#implementation PakkelisteViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.toDoItems = [[NSMutableArray alloc] init];
[self loadInitialData];
// 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)viewWillAppear:(BOOL)animated
{
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"AUFToDoItem"];
self.toDoItems = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
-(void)loadInitialData
{
// check if user has already been using this functionality
BOOL hasRunBefore = [[NSUserDefaults standardUserDefaults] boolForKey:#"PakkelisteHasRun"];
if (!hasRunBefore)
{
NSLog(#"Has not run");
[self.toDoItems addObjectsFromArray:#[#"Badetøy", #"Skrivesaker", #"Lommepenger", #"Godt humør"]];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"PakkelisteHasRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
else
{
NSLog(#"Already run");
}
}
-(IBAction)addNewToDoItem
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Legg til ny" message:nil delegate:self cancelButtonTitle:#"Avbryt" otherButtonTitles:#"Legg til", nil];
[alertView setAlertViewStyle:UIAlertViewStylePlainTextInput];
[[alertView textFieldAtIndex:0] setPlaceholder:#"Rent undertøy"];
[[alertView textFieldAtIndex:0] setAutocapitalizationType:UITextAutocapitalizationTypeSentences];
[alertView show];
}
-(BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
NSString *inputText = [[alertView textFieldAtIndex:0] text];
if ([inputText length] > 0)
{
return YES;
}
else
{
return NO;
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *toDoItem = [NSEntityDescription insertNewObjectForEntityForName:#"AUFToDoItem" inManagedObjectContext:context];
[toDoItem setValue:[alertView textFieldAtIndex:0].text forKey:#"itemName"];
[toDoItem setValue:[NSDate date] forKey:#"creationDate"];
[toDoItem setValue:[NSNumber numberWithBool:YES] forKey:#"completed"];
[self.toDoItems addObject:toDoItem];
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];
[self.tableView reloadData];
}
}
- (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.toDoItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
TodoCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[TodoCell alloc] init];
}
NSManagedObject *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
cell.title.text = [toDoItem valueForKey:#"itemName"];
if ([[toDoItem valueForKey:#"completed"] boolValue] == 1)
{
cell.checkbox.image = [UIImage imageNamed:#"checkbox_on.png"];
}
else
{
cell.checkbox.image = [UIImage imageNamed:#"checkbox_on.png"];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
/*
[tableView deselectRowAtIndexPath:indexPath animated:NO];
AUFToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];
tappedItem.completed = !tappedItem.completed;
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
*/
}
-(NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
[context deleteObject:[self.toDoItems objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Can't delete! %# %#", error, [error localizedDescription]);
return;
}
[self.toDoItems removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] 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.
}
*/
#end

Change:
tappedItem.completed = !tappedItem.completed;
to:
tappedItem.completed = #(![tappedItem.completed boolValue]);
Which is a minimal code unpacking and re packing of the bool value in an NSNumber instance.
Also, in your if statement, don't check if a BOOL value == 1 because that isn't necessarily true. Just say:
if ([tappedItem.completed]) { ...
You also appear to have a typo in the names of the checkbox images you're using.

What if move the code to update the status of your cell in tableView:tableView didSelectRowAtIndexPath:? In addition, can you explain what you mean with But I am not sure how to update Core Data setting the boolean value of completed to yes?
After updating the status of your managed object you save the context you are using, then you can perfom a reload on the entire table or on a specific index path.
BOOL hasTap = ![tappedItem.completed boolValue];
tappedItem.completed = #(hasTap); // or [NSNumber numberWithBool:hasTap];
// save
// reload
I really follow Jonathan's comment. A NSFetchedResultsController is made to wotk with UITableViews (or UICollectionViews). You can set its delegate, NSFetchedResultsControllerDelegate, to listen and handle for inserting, deleting, moving rows (and section).
An tutorial would be Core Data Tutorial for iOS: How To Use NSFetchedResultsController.

Related

Can't do a substring operation with something that isn't a string

I have a database with core data and i am trying to make it searchable. It doesn't work and returns this error:
'Can't do a substring operation with something that isn't a string
(lhs = (entity: Device; id: 0x8c63bc0
; data:
{.......}
So that is my code for creating cells.
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
self.searchResults = [[NSArray alloc]init];
[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)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Device"];
self.devices = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (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
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [self.searchResults count];
}
else
{
return [self.devices count];
}
// Return the number of rows in the section.
// return self.devices.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (tableView == self.searchDisplayController.searchResultsTableView) {
NSManagedObject *device = [self.searchResults objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [device valueForKey:#"text1"]]];
[cell.detailTextLabel setText:[device valueForKey:#"text3"]];
}
else
{
// Configure the cell...
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [device valueForKey:#"text1"]]];
[cell.detailTextLabel setText:[device valueForKey:#"text3"]];
}
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.devices objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.devices 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:#"UpdateJob"]) {
NSManagedObject *selectedDevice = [self.devices objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
JobDetailViewController *destViewController = segue.destinationViewController;
destViewController.device = selectedDevice;
}
}
and the code for the query:
#pragma Search Methods
-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#",searchText];
self.searchResults = [self.devices filteredArrayUsingPredicate:predicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
return YES;
}
but it keeps breaking when i enter the first letter. What can i do?
Not a predicate expert but shouldnt SELF beginswith[c] %# be text1 beginswith[c] %# since the predicate is used on an array of object Device
I've solved it. I've added this line of code.
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// More initializations if needed.
}
just below
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Thanks for all the help guys!

UITableView not being updated after adding new items (using Core Data)

I use Core Data to keep track of entries in a simple to do list. I use a simple UIAlertView with UITextField for the user to add new entries. The entries are saved using NSManagedObject, but the latest entry isn't added to the tableview, even after I run [self.tableView reloadData];
This GIF show how it works now:
Header file:
#import <UIKit/UIKit.h>
#interface PakkelisteViewController : UITableViewController <UIAlertViewDelegate>
#end
Implementation file:
#import "PakkelisteViewController.h"
#import "AUFToDoItem.h"
#interface PakkelisteViewController ()
#property NSMutableArray *toDoItems;
-(IBAction)addNewToDoItem;
#end
#implementation PakkelisteViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// defaultTodos = [[NSMutableArray alloc] initWithObjects:#"Badetøy", #"Skrivesaker", #"Lommepenger", #"Godt humør", nil];
self.toDoItems = [[NSMutableArray alloc] init];
[self loadInitialData];
// 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)viewWillAppear:(BOOL)animated
{
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"AUFToDoItem"];
self.toDoItems = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
-(void)loadInitialData
{
}
-(IBAction)addNewToDoItem
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Legg til ny" message:nil delegate:self cancelButtonTitle:#"Avbryt" otherButtonTitles:#"Legg til", nil];
[alertView setAlertViewStyle:UIAlertViewStylePlainTextInput];
[[alertView textFieldAtIndex:0] setPlaceholder:#"Rent undertøy"];
[[alertView textFieldAtIndex:0] setAutocapitalizationType:UITextAutocapitalizationTypeSentences];
[alertView show];
}
-(BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
NSString *inputText = [[alertView textFieldAtIndex:0] text];
if ([inputText length] > 0)
{
return YES;
}
else
{
return NO;
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *toDoItem = [NSEntityDescription insertNewObjectForEntityForName:#"AUFToDoItem" inManagedObjectContext:context];
[toDoItem setValue:[alertView textFieldAtIndex:0].text forKey:#"itemName"];
[toDoItem setValue:[NSDate date] forKey:#"creationDate"];
[toDoItem setValue:NO forKey:#"completed"];
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];
[self.tableView reloadRowsAtIndexPaths:[self.tableView indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationFade];
// [self.tableView reloadData];
}
}
- (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.toDoItems.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];
}
NSManagedObject *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
cell.textLabel.text = [toDoItem valueForKey:#"itemName"];
if ((BOOL)[toDoItem valueForKey:#"completed"] == YES)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
/*
[tableView deselectRowAtIndexPath:indexPath animated:NO];
AUFToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];
tappedItem.completed = !tappedItem.completed;
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
*/
}
-(NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
[context deleteObject:[self.toDoItems objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error])
{
NSLog(#"Can't delete! %# %#", error, [error localizedDescription]);
return;
}
[self.toDoItems removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] 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.
}
*/
#end
You need to add the new toDoItem to your array as well. Try this :
// Create a new managed object
NSManagedObject *toDoItem = [NSEntityDescription insertNewObjectForEntityForName:#"AUFToDoItem" inManagedObjectContext:context];
[toDoItem setValue:[alertView textFieldAtIndex:0].text forKey:#"itemName"];
[toDoItem setValue:[NSDate date] forKey:#"creationDate"];
[toDoItem setValue:NO forKey:#"completed"];
[self.toDoItems addObject:toDoItem];
[self.tableView reloadData];
You should update your dataSource self.toDoItems as it still stays the same as off in viewDidLoad method. You're only saving it in CoreData, but not refreshing your dataSourse and [tableView reloadData] wont do anything

Core Data Not Saving To Table 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.

Core Data Crashing When Pushing to 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. 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...

SearchBar clickable results - Core Data

I am fairly new to Xcode so I have been using a tutorial on how to implement a SearchBar in my notes app. The SearchBar retrieves the data from the table view but when I click on it it doesn't take me to the page. How would I fix this problem in UIStoryboardSegue keeping in mind I'm new to all this stuff! Thanks in advance:3
#import "DeviceViewController.h"
#import "DeviceDetailViewController.h"
#interface DeviceViewController ()
#property (strong) NSMutableArray *devices;
#end
#implementation DeviceViewController
{
NSArray *searchResults;
}
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
//label.backgroundColor = [UIColor clearColor];
label.font = [UIFont fontWithName:#"HelveticaNeue-thin" size:28];
//label.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.5];
label.textColor = [UIColor blackColor];
self.navigationItem.titleView = label;
label.text = #"TapNotes";
[label sizeToFit];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Device"];
self.devices = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (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
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [searchResults count];
} else {
return self.devices.count;
}
//return self.devices.count;
}
- (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:CellIdentifier]; }
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [device valueForKey:#"name"]]];
[cell.detailTextLabel setText:[NSString stringWithFormat:#"%#",[device valueForKey:#"version"]]];
if (tableView == self.searchDisplayController.searchResultsTableView) {
device = [searchResults objectAtIndex:indexPath.row];
} else {
[self.devices objectAtIndex:indexPath.row];
}
// cell.thumbnailImageView.image = [UIImage imageNamed:recipe.image];
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.devices objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.devices removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
/*
// 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
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// 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;
}
*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"UpdateDevice"]) {
NSManagedObject *selectedDevice = [self.devices objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
NSIndexPath *indexPath = nil;
//Device *device = nil;
if (self.searchDisplayController.active) {
indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
_devices = [searchResults objectAtIndex:indexPath.row];
} else {
indexPath = [self.tableView indexPathForSelectedRow];
_devices = [_devices objectAtIndex:indexPath.row];
}
DeviceDetailViewController *destViewController = segue.destinationViewController;
destViewController.device = selectedDevice;
}
}
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"name contains[c] %#", searchText];
searchResults = [_devices filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString
scope:[[self.searchDisplayController.searchBar scopeButtonTitles]
objectAtIndex:[self.searchDisplayController.searchBar
selectedScopeButtonIndex]]];
return YES;
}
#end
A UIStoryboardSegue can only be connected via a storyboard. Since you are presenting your search data through the UISearchDisplayController, you need to implement tableView:didSelectRowAtIndexPath:. In this method you need to make sure you are only performing a push to a new view controller when you are receiving events from the tableview connected to UISearchDisplayController In this method I would recommend you to use performSegueWithIdentifier: and manually connect a segue in you storyboard. See this answer for more details on how to create a manual segue: https://stackoverflow.com/a/17012857/1049509

Resources