Search code examples
objective-cdelegatesuinavigationcontrollerpopviewcontrolleranimated

UIViewController in a UINavigationController not calling delegate method


In my Storyboard, I am using a UINavigationController with a navigation bar to present a view controller. This view controller, ViewController2, is pushed to the stack by tapping a UIBarButtonItem that I placed in the navigation bar. I made this connection in Interface Builder by dragging from the bar button to the ViewController2 scene and selecting "push" for the segue. To return back to the first view controller, I have an IBAction that calls the popViewControllerAnimated method. I'm using the delegate method to send data back to the first view controller but the string from ViewController2 is not being sent back to ViewController.

How can I pass the text entered in ViewController2 back to the first ViewController using the delegate method?

ViewController.h

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end

ViewController.m

#import "ViewController.h"
#import "ViewController2.h"

@interface ViewController () <UITableViewDelegate,UITableViewDataSource,Vc2Delegate>

@property (strong,nonatomic) NSArray *tableArray;
@property (weak,nonatomic) IBOutlet UITableView *listTableView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.listTableView setDelegate:self];
    [self.listTableView setDataSource:self];

    self.tableArray = @[@"item 1",@"item 2",@"item 3"];

    ViewController2 *vc2 = [[ViewController2 alloc] init];
    [vc2 setDelegate:self];
}

# pragma mark - TableView

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.tableArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ItemCell" forIndexPath:indexPath];
    cell.textLabel.text = [self.tableArray objectAtIndex:indexPath.row];

    return cell;
}

#pragma mark - Delegate Method

- (void)returnFromVc2:(NSString *)userString {
    NSLog(@"delegate text is %@",userString);
}

@end

ViewController2.h

#import <UIKit/UIKit.h>

@protocol Vc2Delegate <NSObject>

- (void)returnFromVc2:(NSString *)userString;

@end

@interface ViewController2 : UIViewController

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

@end

ViewController2.m

#import "ViewController2.h"

@interface ViewController2 ()

@property (weak,nonatomic) IBOutlet UITextField *textField;

@end

@implementation ViewController2

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (IBAction)toPreviousVC:(id)sender {
    NSLog(@"user text is: %@",self.textField.text);

    [self.delegate returnFromVc2:self.textField.text];

    [self.navigationController popViewControllerAnimated:YES];
}

@end

Solution

  • You set the delegate to a local variable that won't be the same instance as the one you push.

    - (void)viewDidLoad {
        ....
        ViewController2 *vc2 = [[ViewController2 alloc] init];
        [vc2 setDelegate:self];
        ....
    }
    

    You should also make a habit of checking if your delegate can respond to the message sent.

    - (IBAction)toPreviousVC:(id)sender {
        NSLog(@"user text is: %@",self.textField.text);
    
        if ( [self.delegate respondsToSelector(@selector(returnFromVc2:))] ) {
            [self.delegate returnFromVc2:self.textField.text];
        }
        [self.navigationController popViewControllerAnimated:YES];
    }