89128

How to pass an object in a segue rather that a detail of an object?

Question:

I have a simple notes app where I have just 2 view controllers:

<ol><li>table view controller - to list all the notes.</li> <li>view controller - to create new notes.</li> </ol>

In the table view controller I have a segue from a cell back to the creation page where a user can edit the note in this specific cell.

But my problem is that when I'm preforming editing to a certain cell(note) I'm creating a new note with the content of what I edited...

So instead of passing the note content in the prepareForSegue method I need to pass the note object...

How can I do that?

this are my classes:

NMNote: (correctly just containing a property of *content, will add more behaviour later)

#import <Foundation/Foundation.h> @interface NMNote : NSObject @property (strong, nonatomic) NSString *content; @end

NMCreateNotesViewController.h:

#import <UIKit/UIKit.h> #import "NMNote.h" @interface NMCreateNotesViewController : UIViewController @property (strong, nonatomic) NMNote *note; @property (weak, nonatomic) IBOutlet UITextView *textField; @property (strong, nonatomic) NSString *passedInString; @end

NMCreateNotesViewController.m:

#import "NMCreateNotesViewController.h" #import "NMNotesListViewController.h" @interface NMCreateNotesViewController () <UITextViewDelegate> @property (weak, nonatomic) IBOutlet UIBarButtonItem *saveButton; @end @implementation NMCreateNotesViewController - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // 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]; } #pragma mark - Notifications - (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.textField.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.textField.frame = frame; [UIView commitAnimations]; } - (void)keyboardWillShow:(NSNotification *)aNotification { [self adjustViewForKeyboardReveal:YES notificationInfo:[aNotification userInfo]]; } - (void)keyboardWillHide:(NSNotification *)aNotification { [self adjustViewForKeyboardReveal:NO notificationInfo:[aNotification userInfo]]; } - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if (sender != self.saveButton) return; if (self.textField.text.length > 0) { self.note = [[NMNote alloc] init]; self.note.content = self.textField.text; } } - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; if (self.passedInString != nil) { self.textField.text = self.passedInString; } // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end

NMNotesListViewController.h:

#import <UIKit/UIKit.h> @interface NMNotesListViewController : UITableViewController - (IBAction) unwindToList: (UIStoryboardSegue *) segue; @end

NMNotesListViewController.m:

#import "NMNotesListViewController.h" #import "NMCreateNotesViewController.h" @interface NMNotesListViewController () @property (strong, nonatomic) NSMutableArray *notes; @end @implementation NMNotesListViewController - (IBAction) unwindToList: (UIStoryboardSegue *) segue { NMCreateNotesViewController *source = [segue sourceViewController]; NMNote *note = source.note; if (note != nil) { [self.notes addObject:note]; [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]; // 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.notes count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"NotesPrototypeCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; // Configure the cell... NMNote *note = [self.notes objectAtIndex:indexPath.row]; cell.textLabel.text = note.content; return cell; } - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(UITableViewCell *)sender { if ([[segue identifier] isEqualToString:@"noteSegue"]) { NMCreateNotesViewController *destination = [segue destinationViewController]; NSInteger indx = [self.tableView indexPathForCell:sender].row; NMNote *note = self.notes[indx]; destination.passedInString = note.content; } } //#pragma mark - delegate // //- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath //{ // //} @end

This is the screens flow:

the initiate view is this table view:

<img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/lFK3n.png" data-original="https://i.stack.imgur.com/lFK3n.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

Now there is the TextView where you write the note:

<img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/tmFP6.png" data-original="https://i.stack.imgur.com/tmFP6.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

Now, after you save a note, you go back to the first screen. and then you can tap on a populated cell and you will segue back to this screen (the one with the TextView) so you can edit it. But instead of editing it, it will create a new one with the edited content. like this:

<img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/osByc.png" data-original="https://i.stack.imgur.com/osByc.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

Please, would appreciate any help here to accomplish my task.. Thanks!

Answer1:

The thing you need to do when you pass the note to the NMCreateNotesViewController, is to differentiate between an edit and an add action so when you came back to the table view, you can either replace the old entry with the new edited one, or add a new entry.

The way I would approach this is to have two segues, one from the + button (I'll call it "addSegue") and one from the table view cell (call it "editSegue"). I would also create a property in the list controller to hold the value of the edited row, or set it to something like -1 to indicate it's a new note. Something like this,

@property (nonatomic) NSInteger editedRow; - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"editSegue"]) { NMCreateNotesViewController *destination = [segue destinationViewController]; NSInteger indx = [self.tableView indexPathForCell:(UITableViewCell *)sender].row; self.editedRow = index; NMNote *note = self.notes[indx]; destination.note = note; }else if ([segue.identifier isEqualToString:@"addSegue"]) { self.editedRow = -1; }

The prepareForSegue method in the NMCreateNotesViewController would be the same as you have in your question. You can get rid of the passedInString property since we're passing in the entire note object instead. In the unwind method in the list controller, you would do this,

- (IBAction) unwindToList: (UIStoryboardSegue *) segue { NMCreateNotesViewController *source = [segue sourceViewController]; NMNote *note = source.note; if (note != nil && self.editedRow == -1) { [self.notes addObject:note]; }else{ [self.notes replaceObjectAtIndex:self.editedRow withObject:note]; } [self.tableView reloadData]; }

Answer2:

in NMCreateNotesViewController.h:

@property (strong, nonatomic) NMNote *note; @property BOOL adding; @property (strong,nonatomic) NSString *originalContent;

Then in your NMNotesListViewController.m prepareForSegue

destination.note=self.notes[indx]; destination.adding=NO; // set adding to yes if you are adding a new note

and in your unwind

- (IBAction) unwindToList: (UIStoryboardSegue *) segue { NMCreateNotesViewController *source = [segue sourceViewController]; NMNote *note = source.note; if (source.adding && note != nil) { [self.notes addObject:note]; [self.tableView reloadData]; } }

in NMCreateNotesViewController.m

- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // 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]; if (self.note != nil) { self.originalContent=self.note.content; self.textField.text=self.note.content; } } - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if (sender != self.saveButton) { if (self.note != nil) { self.note.content=self.originalContent; } } else { if (self.note == nil) { if (self.textField.text.length > 0) { self.note = [[NMNote alloc] init]; } self.note.content = self.textField.text; } }

Recommend