3

Edit 1: I think I have figured out the problem, I just haven't been able to solve it. In SecondViewController.m where textFieldShouldReturn is defined, "if ([self.delegate respondsToSelector:@selector(passString:)])" returns false, since NSLog was not triggered.

Edit 2: Checking NSLogs of who is the delegate in both ViewControllers gave good insight to the problem. In the FirstViewController, prepareForSegue assigns the correct delegate. After the segue to SecondViewController, delegate becomes "null".

This is something I have been trying to achieve for a week without success. I do understand that I need to pass the data back up the two-layer navigation stack using delegates. However, I'm not sure why my code does not work (string does not get passed).

It would be also much appreciated if anyone can tell me (links and other resources) how to properly make a Form/Submission View (2nd Controller) for data entry that can be reused for to edit specific cell's labels in the Display View (1st Controller).

Here is my code:

SecondViewController.h

#import <UIKit/UIKit.h>

@protocol PassStringDelegate
- (void)passString:(NSString *)stringFromTextField;
@end

@interface SecondViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>

@property (strong, nonatomic) IBOutlet UITableView *detailTable;

@property (weak, nonatomic) id <PassStringDelegate> delegate;

@end

SecondViewController.m

#import "SecondViewController.h"
#import "CustomCell.h" // My cell is custom built in IB.

@interface SecondViewController ()

@end

@implementation SecondViewController

@synthesize delegate;

@synthesize stringFromTextField;

- (void)viewDidLoad
{
    ...            
    NSLog(@"%@", self.delegate);                          // Returns "(null)".
}    

...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Data Entry" forIndexPath:indexPath];
    [cell setEditing:YES animated:YES];
    cell.customTextField.clearsOnBeginEditing = NO;
    cell.customTextField.returnKeyType = UIReturnKeyDone;
    cell.customTextField.delegate = self;                 // customTextField is a custom textfield embedded in the custom cell.
    [self textFieldShouldReturn:cell.customTextField];    // This function supposedly will trigger passString:stringFromTextField when the cell is done with editing.

    return cell;
}

...

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    if ([self.delegate respondsToSelector:@selector(passString:)]) {
        [self.delegate passString:textField.text];
        NSLog(@"Sent back: %@", textField.text);          // I checked NSLog, this was never called.
    }
    return YES;
}

FirstViewController.h

#import <UIKit/UIKit.h>
#import "SecondViewController.h"

@interface FirstViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate, PassStringDelegate>

@property (strong, nonatomic) IBOutlet UITableView *table;

@property (copy, nonatomic) NSArray *myList;

@property (weak, nonatomic) NSString *obtainedString;

@end

FirstViewController.m

#import "FirstViewController.h"
#import "CustomCell.h"

@interface FirstViewController ()

@end

@implementation FirstViewController

@synthesize obtainedString;

...

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self passString:obtainedString];
}

...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Display" forIndexPath:indexPath];
    cell.customLabel.text = obtainedString;             // I want the label to display the text in the text field in the second controller.
    cell.detailCustomLabel.text = self.myList[indexPath.row];

    return cell;
}

...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"segue"])
     {
        SecondViewController *detailedView = [[SecondViewController alloc] init];
        detailedView.delegate = self;
        NSLog(@"%@", detailedView.delegate);            // Returns "<SecondViewController: 0x10967b590>".
     }
}

...

- (void)passString:(NSString *)stringFromTextField
{
    obtainedString = stringFromTextField;
}

Please check my delegate path and calls to see if what I did was close to appropriate. Thank you very much!

2 Answers2

2

Try this:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"segue"]) {
        //SecondViewController *detailedView = [[SecondViewController alloc] init];
        //this creates a new object of SecondViewController that has nothing to do
        //with the segue

        //this should fix it:
        SecondViewController *detailedView = [segue destinationViewController];
        detailedView.delegate = self;
    }
}

You were creating a new object of SecondViewController and setting a delegate on it.
Sadly, this object was not being used at all since the segue has already created an object and pushing that object instead of the one you instantiate here.

staticVoidMan
  • 19,275
  • 6
  • 69
  • 98
  • Fantastic! I forgot about the [segue destinationViewController] part! Although the text in the text field still does not display, NSLog in FirstViewController has at least received the text field's text. Thank you :D If you don't mind to also help me fix the text display I would really appreciate it. – Stack Asker Aug 31 '14 at 16:11
  • @StackAsker :) great. as for text display... not sure about that (_right now_) but it could be due to `obtainedString` being of `weak` reference. Make it `strong` and check. – staticVoidMan Aug 31 '14 at 16:14
  • @StackAsker : wait, shouldn't you use `obtainedString` in someway? Seems your `-passString:` method is incomplete. – staticVoidMan Aug 31 '14 at 16:18
  • That's one more step closer to the full solution. whatever typed in the textfield is now retained when second view is dismissed. Now it's just the matter of the logic behind passing that value into cell.customLabel.text. I tried reloading the table in viewDidAppear but that did nothing. – Stack Asker Aug 31 '14 at 16:22
  • What I did was to get the value of the text field and transfer it to obtainedString. Then in the cellForRowAt... method I wrote: "cell.customLabel.text = obtainedString;". – Stack Asker Aug 31 '14 at 16:24
  • Oh... i see... hm... `-cellForRowAtIndexPath:`. You know... you'll need a bit more wiring up to do for `obtainedString` to be used in this fashion. Sorry but I gotta go for now. I'll look into it later if you haven't found a solution by then :). For now, `[self.tableView reloadData];` might work – staticVoidMan Aug 31 '14 at 16:24
  • That would be appreciated thank you :D Have a good one, see ya later! – Stack Asker Aug 31 '14 at 16:25
  • @StackAsker : so, what's the scene now? I'd defer the `-reloadData` task until just when the `viewController` is going to be displayed. – staticVoidMan Sep 01 '14 at 05:41
0

Add a property @property (retain) FirstViewControllor *parentController in second viewcontrollor and before u push SecondViewControllor

add

secondviewcontrollor.parentController=self;

and in

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    (FirstViewControllor)self.parentController.obtainedString=textField.text;
}
Emel Elias
  • 572
  • 7
  • 18