-1

I have been struggling with this for a few days and have received valuable help on the way from S.O. I have made the simplest possible project to reduce the possibilities of it being a typo. All my project is, is a ViewController that holds a container view hooked to a childViewController. The "parent" ViewController is set as the delegate of the childViewController. In the viewDidLoad of the child I am passing a value which is just a string. This string should be passed on to the parent and printed on the console. Here are the files.

ViewController.h

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

@interface ViewController : UIViewController <ChildViewControllerDelegate>

@end

ViewController.m

#import "ViewController.h"

@interface ViewController ()

@property NSString *myValueRetrieved;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

   ChildViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"ChildVC"];

    controller.delegate = self;

    NSLog(@"Here is my value: %@",self.myValueRetrieved);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

- (void) passValue:(NSString *)theValue{

    self.myValueRetrieved = theValue;
}

@end

ChildViewController.h

#import <UIKit/UIKit.h>

@protocol ChildViewControllerDelegate;

@interface ChildViewController : UIViewController

@property (weak)id <ChildViewControllerDelegate> delegate;

@end

@protocol ChildViewControllerDelegate <NSObject>

- (void) passValue:(NSString*) theValue;

@end

ChildViewController.m

#import "ChildViewController.h"

@interface ChildViewController ()
@property NSArray *colors;
@end

@implementation ChildViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.delegate passValue:@"Hello"];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

Am I right to think that when the app is launched, the console should log the following message: "here is my value: hello". Am I doing something wrong in terms of logically not getting delegation or is it just a silly typo somewhere? tx

Paul
  • 1,277
  • 5
  • 28
  • 56

2 Answers2

0

You're assuming that the view is loaded when the view controller is instantiated. That's now how it works. The view gets loaded when it's needed (like to add to the parent view).

But you can force the view to load and make this work. Call -loadViewIfNeeded on the child view controller right after setting the delegate. That will probably get you what you want:

controller.delegate = self;
[controller loadViewIfNeeded];
NSLog(@"Here is my value: %@",self.myValueRetrieved);

Or, if you do want to call back the delegate in viewDidLoad, then you'd need to move the NSLog to the -passValue: method, since the primary view controller's viewDidLoad method will have already finished running.

Dave Batton
  • 8,795
  • 1
  • 46
  • 50
  • [controller loadViewIfNeeded]; is crashing the app. The thing that I don't fully understand is how is "theValue" receiving anything. If it's a method like the other ones, shouldn't I be able to call it in viewDidLoad like so: [self passValue:] the thing is I don't want to pass an argument there, I want theValue. Does the question make sense? – Paul Jan 25 '16 at 23:40
0

To do this make ParentController a delegate of ChildController. This allows ChildController to send a message back to ParentController enabling us to send data back.

For ParentController to be delegate of ChildController it must conform to ChildController's protocol which we have to specify. This tells ParentController which methods it must implement.

In ChildController.h, below the #import, but above @interface you specify the protocol.

@class ChildController;

@protocol ViewControllerBDelegate <NSObject>
- (void)addItemViewController:(ChildController *)controller didFinishEnteringItem:(NSString *)item;
@end

next still in the ChildController.h you need to setup a delegate property and synthesize in ChildController.h

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

In ChildController we call a message on the delegate when we pop the view controller.

NSString *itemToPassBack = @"Pass this value back to ParentController";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];

That's it for ChildController. Now in ParentController.h, tell ParentViewController to import Child and conform to its protocol.

import "ChildController.h"

@interface ParentController : UIViewController In ParentController.m implement the following method from our protocol

- (void)addItemViewController:(ChildController *)controller didFinishEnteringItem:(NSString *)item
{
    NSLog(@"This was returned from ChildController %@",item);
}

The last thing we need to do is tell ChildController that ParentController is its delegate before we push ChildController on to nav stack.

ChildController *ChildController = [[ChildController alloc] initWithNib:@"ChildController" bundle:nil];
ChildController.delegate = self
[[self navigationController] pushViewController:ChildController animated:YES];
Community
  • 1
  • 1
Shravan
  • 438
  • 3
  • 17
  • Hi, Thanks for this, I am following your instructions. I am having the same problem with the last line. "ChildController *ChildController = [[ChildController alloc] initWithNib:@"ChildController" bundle:nil];" – Paul Jan 25 '16 at 23:19
  • It's returning the error: no visible @interface for "ChildController" declares the selector 'initWithNib:bundle:' – Paul Jan 25 '16 at 23:20
  • do not init with nib.... just try this instead nib is used only when u have a nib file... right now i suppose u are using storyboards... for that simply use init. `ChildController *ChildController = [[ChildController alloc] init];` – Shravan Jan 27 '16 at 03:45