Saving data in one view controller and displaying it in another - ios

I am currently developing an app the needs to have an initial setting screen (name, date, amount of deposit, and percentage). I have created a view controller that will add and then save to core data. I can also retrieve the information.
What I need next is to be able to pop into another view controller and enter continuing number for the same person. Whenever i enter data into the second view controller it comes back as an addition as if it were a new person. I need some help to figure it out as i am still new and learning.
Below is the .h and .m files of the two view controllers.
ForexDetailViewController.h
#import <UIKit/UIKit.h>
#interface ForexDetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *nameTextField;
#property (weak, nonatomic) IBOutlet UITextField *startamountTextField;
#property (weak, nonatomic) IBOutlet UITextField *startmonthTextField;
#property (strong, nonatomic) IBOutlet UITextField *startpercentTextField;
#property (weak, nonatomic) IBOutlet UITextField *endmonth1year1TextField;
#property (weak, nonatomic) IBOutlet UITextField *endpercentmonth1year1TextField;
#property (strong) NSManagedObject *device;
- (IBAction)cancel:(id)sender;
- (IBAction)save:(id)sender;
- (IBAction)textFieldReturn:(id)sender;
- (IBAction)calcultae;
#end
ForexDetailViewController.m
#import "ForexDetailViewController.h"
#interface ForexDetailViewController ()
#end
#implementation ForexDetailViewController
- (IBAction)textFieldReturn:(id)sender
{
[sender resignFirstResponder];
}
#synthesize device;
- (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.
if (self.device) {
[self.nameTextField setText:[self.device valueForKey:#"name"]];
[self.startamountTextField setText:[self.device valueForKey:#"startamount"]];
[self.startmonthTextField setText:[self.device valueForKey:#"startmonth"]];
[self.startpercentTextField setText:[self.device valueForKey:#"startpercent"]];
[self.endmonth1year1TextField setText:[self.device valueForKey:#"endmonth1year1"]];
[self.endpercentmonth1year1TextField setText:[self.device valueForKey:#"endpercentmonth1year1"]];
}
}
- (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];
if (self.device) {
// Update existing device
[self.device setValue:self.nameTextField.text forKey:#"name"];
[self.device setValue:self.startamountTextField.text forKey:#"startamount"];
[self.device setValue:self.startmonthTextField.text forKey:#"startmonth"];
[self.device setValue:self.startpercentTextField.text forKey:#"startpercent"];
[self.device setValue:self.endmonth1year1TextField.text forKey:#"startpercent"];
[self.device setValue:self.endpercentmonth1year1TextField.text forKey:#"endpercentmonth1year1"];
} else {
// Create a new device
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Calculations" inManagedObjectContext:context];
[newDevice setValue:self.nameTextField.text forKey:#"name"];
[newDevice setValue:self.startamountTextField.text forKey:#"startamount"];
[newDevice setValue:self.startmonthTextField.text forKey:#"startmonth"];
[newDevice setValue:self.startpercentTextField.text forKey:#"startpercent"];
[newDevice setValue:self.endmonth1year1TextField.text forKey:#"endmonth1year1"];
[newDevice setValue:self.endpercentmonth1year1TextField.text forKey:#"endpercentmonth1year1"];
}
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
TimeLineViewController.h
#import <UIKit/UIKit.h>
#interface TimeLineViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *startamountTextField;
#property (weak, nonatomic) IBOutlet UITextField *endmonth1year1TextField;
#property (weak, nonatomic) IBOutlet UITextField *endpercentmonth1year1TextField;
#property (strong) NSManagedObject *device;
- (IBAction)cancel:(id)sender;
- (IBAction)save:(id)sender;
- (IBAction)textFieldReturn:(id)sender;
#end
TimeLineViewController.m
#import "TimeLineViewController.h"
#interface TimeLineViewController ()
#end
#implementation TimeLineViewController
- (IBAction)textFieldReturn:(id)sender
{
[sender resignFirstResponder];
}
#synthesize device;
- (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.
if (self.device) {
[self.startamountTextField setText:[self.device valueForKey:#"startamount"]];
[self.endmonth1year1TextField setText:[self.device valueForKey:#"endmonthe1year1"]];
[self.endpercentmonth1year1TextField setText:[self.device valueForKey:#"endpercentmonth1year1"]];
}
}
- (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];
if (self.device) {
// Update existing device
[self.device setValue:self.startamountTextField.text forKey:#"startamount"];
[self.device setValue:self.endmonth1year1TextField.text forKey:#"endmonth1year1"];
[self.device setValue:self.endpercentmonth1year1TextField.text forKey:#"endpercentmonth1year1"];
} else {
// Create a new device
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Calculations" inManagedObjectContext:context];
[newDevice setValue:self.startamountTextField.text forKey:#"startamount"];
[newDevice setValue:self.endmonth1year1TextField.text forKey:#"endmonth1year1"];
[newDevice setValue:self.endpercentmonth1year1TextField.text forKey:#"endpercentmonth1year1"];
}
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
ForexViewController.m
#import "ForexViewController.h"
#import "ForexDetailViewController.h"
#interface ForexViewController ()
#property (strong) NSMutableArray *devices;
#end
#implementation ForexViewController
- (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
{
[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:#"Calculations"];
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
{
// 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];
// Configure the cell...
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [device valueForKey:#"name"]]];
[cell.detailTextLabel setText:[device valueForKey:#"startamount"]];
[cell.detailTextLabel setText:[device valueForKey:#"startmonth"]];
[cell.detailTextLabel setText:[device valueForKey:#"startpercent"]];
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.
}
#pragma mark - Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"UpdateDevice"]) {
NSManagedObject *selectedDevice = [self.devices objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
ForexDetailViewController *destViewController = segue.destinationViewController;
destViewController.device = selectedDevice;
}
}
#end

Where is your code that shows how you show each view?
If you're doing this via Storyboard segue's, you should be setting the device property on the view controllers when you're preparing for segue.
Currently, I don't see how self.device is getting set for either of these view controllers so each time the view loads, it think's there isn't a device and therefore creates a new record for one.
A quick example with a storyboard segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"changeDeviceSettings"]) {
SomeViewController *vc = segue.destinationViewController;
vc.device = selectedDeviceGoesHere;
}
}

Related

Delegate not being called when passing back data between Table View Controllers

I am trying to create a setting page for an app that uses Table View Controllers to pass data back changing the detailed text label of the first view controller depending on the text of the selected row of the second Table View Controller. I put a NSLog in under my delegate method on the initial Table View Controller and it is not being called. I am very stuck, any help is greatly appreciated!
Initial VC .h:
// EditAlarmTVC.h (Initial table view controller .h file)
//
#import <UIKit/UIKit.h>
#import "AlarmSoundTVC.h"
#interface EditAlarmTVC : UITableViewController <AlarmSoundDelegate>
#property (weak, nonatomic) IBOutlet UIDatePicker *datePicker;
#property (weak, nonatomic) IBOutlet UITableViewCell *offMethodCell;
#property (weak, nonatomic) IBOutlet UITableViewCell *repeateCell;
#property (weak, nonatomic) IBOutlet UITableViewCell *alarmLabelCell;
#property (weak, nonatomic) IBOutlet UITableViewCell *alarmSoundCell;
#property (strong) NSManagedObjectModel *alarm;
- (IBAction)cancelSetAlarm:(id)sender;
- (IBAction)saveSetAlarm:(id)sender;
#end
Initial VC .m:
//EditAlarmTVC.m (Initial table view controller.m file)
#import "EditAlarmTVC.h"
#import <CoreData/CoreData.h>
#interface EditAlarmTVC ()
#property (weak, nonatomic) IBOutlet UITableView *myTableView;
#property (retain, nonatomic) NSMutableArray *detailedTextLabels;
#end
#implementation EditAlarmTVC
#synthesize alarm;
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"offMethod"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"timePicker"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"repeateLabelSoundCell"];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"deleteAlarmCell"];
self.detailedTextLabels =[NSMutableArray array];
[self.detailedTextLabels addObject:#"Off"];
[self.detailedTextLabels addObject:#"Never"];
[self.detailedTextLabels addObject:#"Wake up, get up!"];
[self.detailedTextLabels addObject:#"Default"];
}
-(void) viewWillAppear:(BOOL)animated{
[self.offMethodCell.detailTextLabel setText:[self.detailedTextLabels objectAtIndex:0]];
[self.repeateCell.detailTextLabel setText:[self.detailedTextLabels objectAtIndex:1]];
[self.alarmLabelCell.detailTextLabel setText:[self.detailedTextLabels objectAtIndex:2]];
[self.alarmSoundCell.detailTextLabel setText:[self.detailedTextLabels objectAtIndex:3]];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)sendSelection:(NSString *)selectedAlarm{
NSLog(#"hello");
[self.detailedTextLabels replaceObjectAtIndex:3 withObject:selectedAlarm];
[self.myTableView reloadData];
}
-(NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context =nil;
id delegat = [[UIApplication sharedApplication] delegate];
if ([delegat respondsToSelector:#selector(managedObjectContext)]) {
context = [delegat managedObjectContext];
}
return context;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section ==2 & indexPath.row==0){
[self performSegueWithIdentifier:#"repeateSegue" sender:indexPath];
} else if (indexPath.section ==2 & indexPath.row==1){
[self performSegueWithIdentifier:#"alarmLabelSegue" sender:indexPath];
} else if (indexPath.section ==0 & indexPath.row==0){
[self performSegueWithIdentifier:#"offMethodSegue" sender:indexPath];
} else if (indexPath.section ==2 & indexPath.row==2){
[self performSegueWithIdentifier:#"alarmSoundSegue" sender:indexPath];
} else if (indexPath.section ==3 & indexPath.row==0){
//DELETE ALARM
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Alarm" inManagedObjectContext:context];
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc]init];
[timeFormatter setDateFormat:#"h:mm"];
NSDate *timeNSDate = [self.datePicker date];
NSString *timeString = [timeFormatter stringFromDate:timeNSDate];
NSDateFormatter *amPmFormatter = [[NSDateFormatter alloc]init];
[amPmFormatter setDateFormat:#"a"];
NSDate *amPmNSDate = [self.datePicker date];
NSString *amPmString = [amPmFormatter stringFromDate:amPmNSDate];
NSPredicate *p1 = [NSPredicate predicateWithFormat:#"time == %#", timeString];
NSPredicate *p2 = [NSPredicate predicateWithFormat:#"amPm == %#", amPmString];
NSPredicate *p3 = [NSPredicate predicateWithFormat:#"offMethod == %#", self.offMethodCell.detailTextLabel.text];
NSPredicate *p4 = [NSPredicate predicateWithFormat:#"repeate == %#", self.repeateCell.detailTextLabel.text];
NSPredicate *p5 = [NSPredicate predicateWithFormat:#"alarmSound == %#", self.alarmSoundCell.detailTextLabel.text];
NSPredicate *p6 = [NSPredicate predicateWithFormat:#"alarmLabel == %#", self.alarmLabelCell.detailTextLabel.text];
NSPredicate *alarmsPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:#[p1, p2, p3, p4, p5, p6]];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate:alarmsPredicate];
NSError *error;
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *managedObject in items)
{
[context deleteObject:managedObject];
}
EditAlarmTVC *goToEditAlarmTVC = [self.storyboard instantiateViewControllerWithIdentifier:#"setAlarmVC"];
[self.navigationController pushViewController:goToEditAlarmTVC animated:YES];
[self dismissViewControllerAnimated:NO completion:nil];
} else
return;
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"alarmSoundSegue"])
{
AlarmSoundTVC *alarmSoundTVC = [[AlarmSoundTVC alloc]init];
[alarmSoundTVC setDelegate:self];
}
}
#end
Second VC .h:
//AlarmSoundTVC.h (Second table view controller .h file)
#import <UIKit/UIKit.h>
#protocol AlarmSoundDelegate <NSObject>
#required
-(void) sendSelection:(NSString *)selectedAlarm;
#end
#interface AlarmSoundTVC : UITableViewController
#property (strong, nonatomic) IBOutlet UITableView *myTableView;
#property (nonatomic, weak) id <AlarmSoundDelegate> delegate;
#end
Second VC .m:
// AlarmSoundTVC.m (Second table view controller .m file)
#import "AlarmSoundTVC.h"
#import "EditAlarmTVC.h"
#interface AlarmSoundTVC ()
#end
#implementation AlarmSoundTVC
- (void)viewDidLoad {
[super viewDidLoad];
self.myTableView.delegate = self;
}
-(void) viewWillDisappear:(BOOL)animated{
NSIndexPath *indexPath = [self.myTableView indexPathForSelectedRow];
UITableViewCell *selectedCell =[self.myTableView cellForRowAtIndexPath:(indexPath)];
NSString *selectedAlarm = selectedCell.textLabel.text;
[self.delegate sendSelection:selectedAlarm] ;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
#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 {
// }
#end
I am sorry if there is some extra unnecessary code in there. I am a bit new and wanted to be sure I provided plenty of information. Thanks again!
In your prepareForSegue you are setting the delegate on a new, local, instance of AlarmSoundTVC, that will be discarded as soon as the method exits. You need to use the instance that is going to be presented, which can be accessed via the destinationViewController property of the segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"alarmSoundSegue"])
{
AlarmSoundTVC *alarmSoundTVC = (AlarmSoundTVC *)segue.destinationViewController;
[alarmSoundTVC setDelegate:self];
}
}

IOS/Objective C: App crashes with core data - pressing the save button

I'm following this tutorial (https://www.appcoda.com/introduction-to-core-data/) about fetching core data into a table view, save and delete new items. I believe the code is the same, but the app crashes due to:
[AppDelegate managedObjectContext]: unrecognized selector sent to instance 0x7b026800'
Here's the code for TableViewControll:
#import "TableViewController.h"
#import "DetailViewController.h"
#import "AppDelegate.h"
#interface TableViewController ()
#property (strong) NSMutableArray *lisbonSpots;
#end
#implementation TableViewController
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Spot"];
self.lisbonSpots = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.lisbonSpots.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSManagedObject *ls = [self.lisbonSpots objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [ls valueForKey:#"name"]]];
return cell;
}
And the DetailView:
#import "DetailViewController.h"
#import "TableViewController.h"
#import "AppDelegate.h"
#interface DetailViewController ()<UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *spot;
#end
#implementation DetailViewController
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (IBAction)cancel:(UIBarButtonItem *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(UIBarButtonItem *)sender {
NSManagedObjectContext *context = [self managedObjectContext];
// Create a new managed object
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Spot" inManagedObjectContext:context];
[newDevice setValue:self.spot.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];
}
- (void)viewDidLoad {
[super viewDidLoad];
_spot.delegate=self;
}
#end
Why do I get this error? Am I doing something wrong or is the tutorial out of date?
EDIT:
Despite the first answer being correct - the app runs - another issue came up: when I hit the save button it crashes with this log:
'NSInvalidArgumentException', reason: '+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'Spot''
if ([delegate performSelector:#selector(managedObjectContext)]) {
Should be:
if ([delegate respondsToSelector:#selector(managedObjectContext)]) {

Cant perform delegation

I have a table view controller and a view controller.
StackTableViewController - list of strings
HomeViewController - empty view controller with a label
The HomeViewController label should present always the first sting of the StackTableViewController.
I need to make sure if the first string is deleted to present the new first string.
And this is where I have the problem...if I delete the first string and going back to the HomeViewController, the label is still the string I just deleted....And if I terminate the app and open it again, the correct string shown in the label.
This is How I did it so far:
this is the relevant methods in my StackTableViewController.h + .m:
#protocol StackTableViewControllerDelegate <NSObject>
#optional
-(void)didDeleteObject;
#end
#interface StackTableViewController : UITableViewController <UITableViewDataSource,UITableViewDelegate>
#property (strong,nonatomic) id<StackTableViewControllerDelegate> delegate;
#property (strong, nonatomic) NSString *currentTarget;
#end
#import "StackTableViewController.h"
#import "Target.h"
#import "StackTableViewCell.h"
#import "HomeViewController.h"
#import "CoreDataStack.h"
#interface StackTableViewController () <NSFetchedResultsControllerDelegate>
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultController;
#end
#implementation StackTableViewController
- (id)init {
self = [super initWithNibName:#"StackTableViewController" bundle:nil];
if (self) {
// Do something
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
CoreDataStack *stack = [CoreDataStack defaultStack];
[[stack managedObjectContext] deleteObject:target];
[stack saveContext];
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[_delegate didDeleteObject];
}
}
And this is the relevant methods in the HomeViewController.h + .m:
#import <UIKit/UIKit.h>
#import "StackTableViewController.h"
#interface HomeViewController : UIViewController {
StackTableViewController *stackTableViewController;
}
#property (strong, nonatomic) IBOutlet UILabel *homeLabel;
- (IBAction)goToStack:(id)sender;
#import "StackTableViewController.h"
#interface HomeViewController () <StackTableViewControllerDelegate>
#end
#implementation HomeViewController
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
// Do something
stackTableViewController = [[StackTableViewController alloc] init];
stackTableViewController.delegate = self;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self.navigationController setNavigationBarHidden:YES];
self.homeLabel.font = [UIFont fontWithName:#"Candara-Bold" size:40];
self.homeLabel.text = stackTableViewController.currentTarget;
}
- (void)didDeleteObject {
self.homeLabel.text = stackTableViewController.currentTarget;
}
- (IBAction)goToStack:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
CoreDataStack.h +.m:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface CoreDataStack : NSObject
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ (instancetype)defaultStack;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
#import "CoreDataStack.h"
#implementation CoreDataStack
#pragma mark - Core Data stack
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+ (instancetype)defaultStack {
static CoreDataStack *defaultStack;
static dispatch_once_t onceTocken;
dispatch_once (&onceTocken, ^{
defaultStack = [[self alloc] init];
});
return defaultStack;
}
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "digitalCrown.Treats" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Treats" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Treats.sqlite"];
NSError *error = nil;
NSString *failureReason = #"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = #"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#end
Please help me to solve this, I was tying allot of ways but probably i'm missing something that got to do with view controller lifecycle or something.
(the CoreDataStack is a singleton)
tnx!!
I have noticed that you haven't exposed where and how do you go back as you said here:
And this is where I have the problem...if I delete the first string
and going back to the HomeViewController, the label is still the
string I just deleted
You have two choices to fix it:
1) Use viewWillAppear function and update the required text in it.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// get the most recent updates and assign to the UI
self.homeLabel.text = stackTableViewController.currentTarget;
}
So either you have just loaded this UI or coming back from the next UI, this will be going to help to get the latest updates.
2) Before calling popViewControllerAnimated make sure you have updated text.
if (_delegate && [_delegate respondsToSelector:#selector(didDeleteObject)])
{
// updated the UI through delegate
[_delegate didDeleteObject];
}
// This should be call when your work is done, since
// It will start ending the session of this UI so it will obviously
// miss the track of the `_delegate` variable.
[self.navigationController popViewControllerAnimated:YES];
Hope it helps!
I think you just need to reset your currentTarget property after you delete the object:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
CoreDataStack *stack = [CoreDataStack defaultStack];
[[stack managedObjectContext] deleteObject:target];
[stack saveContext];
// The FRC should recognise that the deletion has happened, and consequently have updated its
// indexes, so the following will access the NEW first item, even if it has just changed:
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[_delegate didDeleteObject];
}
}
I think you'd be better off setting up your variables differently. Specifically, it seems like you would be better off to have a singleton object that holds and manages the stack for you, but here's a way to do what you have set up. I've written a basic app that includes all of its UI in code. Here are the pertinent files:
// AppDelegate.h
// StackTableTesting
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
// AppDelegate.m
// StackTableTesting
#import "AppDelegate.h"
#import "HomeViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
HomeViewController *vc = [[HomeViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
nav.navigationBar.translucent = NO;
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
#end
// Created by Michael McEvoy on 12/23/14.
// Copyright (c) 2014 Mustard Seed Software LLC. All rights reserved.
#import <UIKit/UIKit.h>
#import "StackTableViewController.h"
#interface HomeViewController : UIViewController
#end
// HomeViewController.m
// StackTableTesting
#import "HomeViewController.h"
#import "StackTableViewController.h"
#interface HomeViewController () <StackTableViewControllerDelegate> {
}
#pragma mark -
#pragma mark - Private Properties
#property (strong, nonatomic) StackTableViewController *stackTableViewController;
#property (strong, nonatomic) UILabel *homeLabel;
#end
#pragma mark -
#pragma mark - Implementation
#implementation HomeViewController
#pragma mark -
#pragma mark - Initialization
- (instancetype)init {
self = [super init];
if (self != nil) {
self.stackTableViewController = [[StackTableViewController alloc] init];
self.stackTableViewController.delegate = self;
}
return self;
}
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUserInterface];
}
#pragma mark -
#pragma mark - StackTableViewControllerDelegate Protocol Methods
- (void)didDeleteObject {
self.homeLabel.text = self.stackTableViewController.currentTarget;
}
#pragma mark -
#pragma mark - Button Presses
- (void)goToStack {
[self.navigationController pushViewController:self.stackTableViewController animated:YES];
}
#pragma mark -
#pragma mark - UI Setup
// This is because there's no Storyboard
- (void)setupUserInterface {
self.homeLabel = [[UILabel alloc] init];
self.homeLabel.font = [UIFont fontWithName:#"Candara-Bold" size:40];
self.homeLabel.frame = CGRectMake(20, 20, 200, 50);
self.homeLabel.text = self.stackTableViewController.currentTarget;
self.homeLabel.textColor = [UIColor blackColor];
[self.view addSubview:self.homeLabel];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(20, 80, 200, 50);
[button addTarget:self action:#selector(goToStack) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Go To Stack" forState:UIControlStateNormal];
[self.view addSubview:button];
self.view.backgroundColor = [UIColor whiteColor];
}
#end
// StackTableViewController.h
// StackTableTesting
#import <UIKit/UIKit.h>
#protocol StackTableViewControllerDelegate <NSObject>
- (void)didDeleteObject;
#end
#interface StackTableViewController : UITableViewController {
}
#pragma mark -
#pragma mark - Properties
#property (weak, nonatomic) id <StackTableViewControllerDelegate> delegate;
#property (copy, nonatomic) NSString *currentTarget;
#end
// StackTableViewController.m
// StackTableTesting
#import "StackTableViewController.h"
#interface StackTableViewController () {
}
#pragma mark -
#pragma mark - Private Properties
#property (strong, nonatomic) NSMutableArray *stack;
#end
#pragma mark -
#pragma mark - Implementation
#implementation StackTableViewController
#pragma mark -
#pragma mark - Initialization
- (instancetype)init {
self = [super init];
if (self != nil) {
self.stack = [NSMutableArray array];
for (int i = 0; i < 10; i = i + 1) {
[self.stack addObject:[NSString stringWithFormat:#"Item %d", i + 1]];
self.currentTarget = self.stack[0];
}
}
return self;
}
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
}
#pragma mark -
#pragma mark - UITableViewDataSource Protocol Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.stack.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.textLabel.text = self.stack[indexPath.row];
return cell;
}
#pragma mark -
#pragma mark - UITableViewDelegate Protocol Methods
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
[self.stack removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
self.currentTarget = self.stack[0];
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[_delegate didDeleteObject];
}
}
#end
I think this setup does what you're trying to do, based on your question.
Just set the label value again when HomeViewController appear again. That should work since you said that re-launching the app. solves the problem. This should work too.
- (void)viewWillAppear:(BOOL)animated {
self.homeLabel.text = stackTableViewController.currentTarget;
}
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
// Do something
stackTableViewController = [[StackTableViewController alloc] init];
stackTableViewController.delegate = self;
}
return self;
}
Here, you create a StackTableViewController and set self as the delegate. This is fine.
- (IBAction)goToStack:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
Here, you create a brand new StackTableViewController and push it, without setting the delegate object. Any changes you do in the pushed view controller won't be fed back to the home view controller because the delegate is not set.
Either push your existing stackViewController, or set the delegate on your newly created one.
As an additional point, this:
#property (strong,nonatomic) id<StackTableViewControllerDelegate> delegate;
Coupled with this:
#interface HomeViewController : UIViewController {
StackTableViewController *stackTableViewController;
}
And the fact you're setting the delegate of the stack table view controller to the home view controller (which owns the stack table view controller) means you're creating a strong reference cycle. Delegates are normally weak references for this purpose.

how to use ABRecordGetRecordID to fill up a table with contactinformation

I have a sqlite database where i store ABRecordGetRecordID's of a contact.
I convert the ABRecordGetRecordID's to an NSNumber to store it in the database:
2014-05-21 14:35:12.122 ProjectMobile[17858:60b] 179962464 <-- this is the kind of number i get when i log the following:
#import "HulpViewcontroller.h"
#import "AidTableViewcell.h"
#property UIColor * firstColor;
#property UIColor * secondColor;
#property NSMutableArray *Personen;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
#implementation HulpViewController
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.Personen count];
}
- (IBAction)pickPerson:(id)sender {
ABPeoplePickerNavigationController *picker =
[[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentViewController:picker animated:YES completion:nil];
}
- (void)peoplePickerNavigationControllerDidCancel: (ABPeoplePickerNavigationController *)peoplePicker {
[[peoplePicker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
// Create a new person
NSManagedObject *newPersoon = [NSEntityDescription insertNewObjectForEntityForName:#"Personen" inManagedObjectContext:self.context];
NSNumber *id = [NSNumber numberWithInt:ABRecordGetRecordID(person)];
NSNumber *one = [NSNumber numberWithInt:1];
NSLog(#"%d", id);
[newPersoon setValue: id forKey:#"persoonId"];
[newPersoon setValue: one forKey:#"importance"];
NSError *error = nil;
// Save the object to persistent store
if (![self.context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[[peoplePicker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
return NO;
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property
identifier:(ABMultiValueIdentifier)identifier
{
return NO;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"hulpCell";
AidTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[AidTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// check if row is odd or even and set color accordingly
if (indexPath.row % 2) {
cell.backgroundColor = self.firstColor;
}else {
cell.backgroundColor = self.secondColor;
}
return cell;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.firstColor = [UIColor colorWithRed:183/255.0f green:80/255.0f blue:23/255.0f alpha:1.0f];
self.secondColor = [UIColor colorWithRed:179/255.0f green:98/255.0f blue:0/255.0f alpha:1.0f];
self.Personen = [[NSMutableArray alloc]initWithObjects:#"Man.jpeg", #"Doctor.jpeg", #"Son.jpeg", nil];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self context];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Personen"];
self.personen = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#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
How can i use the Id i stored in the database to put information of the contacts of those id's in a tableview?
I updated the code. This way it will be easier for you guys to help me out :)
Thanks!
You could e.g. do something like this:
CFErrorRef error = nil;
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions (NULL, &error);
if (addressBookRef != nil) {
ABRecordID recordID = yourPersonRecordID; // Assign here your ID
ABRecordRef nxtABRecordRef = ABAddressBookGetPersonWithRecordID (addressBookRef, recordID);
// Do anything with your record, e.g.
ABMultiValueRef addressesRef = ABRecordCopyValue(nxtABRecordRef, kABPersonAddressProperty);
if (addressesRef != nil) {
for (int index = 0; index < ABMultiValueGetCount(addressesRef); index++) {
NSDictionary *addressDictionary = (__bridge_transfer NSDictionary*) ABMultiValueCopyValueAtIndex(addressesRef,index);
// Do something with the persons data
} // for all addresses
CFRelease(addressesRef);
}
CFRelease(addressBookRef);
} else {
NSLog(#"Could not open address book");
}

Fail to pass object data to second view controller

I have a simple notes project, where I only have 2 controllers:
NotesListViewController
CreateNotesViewController
In my prepareForSegue method in the CreateNotesViewController i'm setting the note property to the TextView text property, and than i'm getting it in my unwindToList method in the NotesListViewController.
But when I run the app I'm getting an error in the line of code where I want to add the recieivedNote to my notes array (in the NotesListViewController).
My view controllers are pretty short so I hope you don't mind me sharing both of them:
(I also just learning core data basics and tried to implement it in here so it might caused the problem)
CreateNotesViewController.m:
#import "CreateNotesViewController.h"
#interface CreateNotesViewController ()
#property (weak, nonatomic) IBOutlet UIBarButtonItem *saveButton;
#property (weak, nonatomic) IBOutlet UITextView *myTextView;
#end
#implementation CreateNotesViewController
- (NSManagedObjectContext *) managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]){
context = [delegate managedObjectContext];
}
return context;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton) return;
else if (self.myTextView.text.length > 0) {
[self.note awakeFromInsert];
self.note.content = self.myTextView.text;
NSManagedObjectContext *context = [self managedObjectContext];
// creating a new managed object
NSManagedObject *newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Note" inManagedObjectContext:context];
[newNote setValue:self.myTextView.text forKey:#"content"];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.myTextView.text = self.note.content;
// listen for keyboard hide/show notifications so we can properly adjust the table's height
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)adjustViewForKeyboardReveal:(BOOL)showKeyboard notificationInfo:(NSDictionary *)notificationInfo
{
// the keyboard is showing so ƒ the table's height
CGRect keyboardRect = [[notificationInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration =
[[notificationInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.myTextView.frame;
// the keyboard rect's width and height are reversed in landscape
NSInteger adjustDelta = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? CGRectGetHeight(keyboardRect) : CGRectGetWidth(keyboardRect);
if (showKeyboard)
frame.size.height -= adjustDelta;
else
frame.size.height += adjustDelta;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.myTextView.frame = frame;
[UIView commitAnimations];
}
- (void)keyboardWillShow:(NSNotification *)aNotification
{
[self adjustViewForKeyboardReveal:YES notificationInfo:[aNotification userInfo]];
}
- (void)keyboardWillHide:(NSNotification *)aNotification
{
[self adjustViewForKeyboardReveal:NO notificationInfo:[aNotification userInfo]];
}
- (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.
}
#end
NotesListViewController.m
#import "NotesListViewController.h"
#import "Note.h"
#import "CreateNotesViewController.h"
#interface NotesListViewController ()
#property (nonatomic, strong) NSMutableArray *notes;
#property (nonatomic) NSInteger editedRow;
#end
#implementation NotesListViewController
- (NSManagedObjectContext *) managedObjectContext
{
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]){
context = [delegate managedObjectContext];
}
return context;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"editSegue"]) {
CreateNotesViewController *destination = (CreateNotesViewController *)[segue destinationViewController];
NSInteger indx = [self.tableView indexPathForCell:sender].row;
Note *noteToPass = self.notes[indx];
destination.note = noteToPass;
self.editedRow = indx;
} else if ([[segue identifier] isEqualToString:#"addSegue"]) {
self.editedRow = -1;
}
}
- (IBAction)unwindToList:(UIStoryboardSegue *)segue
{
CreateNotesViewController *source = (CreateNotesViewController *)[segue sourceViewController];
Note *recieivedNote = source.note;
if (recieivedNote != nil && self.editedRow == -1) {
[self.notes addObject:recieivedNote];
} else {
//this is the line that i get the error in:
[self.notes replaceObjectAtIndex:self.editedRow withObject:recieivedNote];
}
[self.tableView reloadData];
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.notes = [[NSMutableArray alloc] init];
}
- (void) viewWillAppear
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Note"];
self.notes = [[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 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.notes.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *noteToDisplay = [self.notes objectAtIndex:indexPath.row];
//Note *noteToDisplay = [self.notes objectAtIndex:indexPath.row];
cell.textLabel.text = [noteToDisplay valueForKey:#"content"];
return cell;
}
#end
Note.h (this is the model, there is nothing in the .m file)
#interface Note : NSManagedObject
#property (nonatomic, retain) NSString * content;
#end
Please help me figure out why am I passing a nil object...
Error screenshot:
Nir, in your NotesListViewController.m and your prepareForSegue:sender: method, you include the following line of code.
destination.note = noteToPass;
By my understanding, in this line of code you are attempting to set the property note in the destination view controller CreateNotesViewController.m:, however the property note does not exist.
Look at including a note public property (declared in CreateNotesViewController.h - so that it is public i.e. accessible by other classes and more importantly your NotesListViewController class). You will also need to import Note.h.
The two extra lines of code in your CreateNotesViewController.h file would include something like these...
#import "Note.h"
and
#property (nonatomic, strong) Note *note;
Then when you "set" the note property in your the line of code destination.note = noteToPass, in this way you have provided a public property to receive your value for noteToPass.
Does this help?

Resources