Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IBOutlet properties does not update when using prepareForSegue method

I am having problem passing value to a IBOutlet property of destinationViewController but it works fine on ordinary property see code below

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"NewsCellToDetail"]) {        
    testViewController *viewController = segue.destinationViewController;
    viewController.titleLabel.text = @"test"; // set the IBOutlet label text to something
    NSLog(@"%@",viewController.titleLabel.text); // this will output to nil
    viewController.textTest = @"testing2"; // set the property to something
    NSLog(@"%@", viewController.textTest) // this will output the string testing2
}

This is the code for the header file testviewcontroller.h

#import <UIKit/UIKit.h>
@interface NewsDetailViewController : UIViewController
@property (strong, nonatomic) IBOutlet UILabel *titleLabel;
@property (strong, nonatomic) NSString *textTest;
@end

I already synthesize both the property.

Thanks for the help.

like image 874
Sharlon M. Balbalosa Avatar asked Nov 28 '22 18:11

Sharlon M. Balbalosa


1 Answers

I'm a little late coming into this answer, but I ran into this issue recently, and the reason for this would have been obvious if we were still instantiating things manually instead of letting the storyboard handle it. It so happens to be the same reason you never manipulate the view when manually instantiating view controllers: the segue's destinationViewController has not called loadView: yet, which in a storyboard runs through deserializing all the view objects from the associated nib.

An extremely simple way to see this in action:

  1. Create a two ViewController Scenes (ViewController1 and ViewController2)
  2. Add a button to ViewController1 and an action segue from the button to ViewController2
  3. Add a subview to ViewControler2, and an IBOutlet to that subview
  4. In prepareForSegue: of ViewController1, try to reference that subview outlet of ViewController2 - you'll find it's nil and its frame/bounds are null.

This is because ViewController2's view has not yet been added to view stack, but the controller has been initialized. Thus, you should never try to manipulate ViewController2's view in prepareForSegue: or otherwise anything you do will be lost. Reference Apple's ViewController Programming Guide here for the lifecycle: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html

The accepted answer here is forcing loadView to run in prepareForSegue: by accessing the .view property of the destination which is why things show up out of order, and will have unknown / difficult to reproduce results if you're trying to do any kind of view manipulation in viewDidLoad to account for any data loads, because without having the view loaded to the viewStack, any references to the parent view for frame references will be nil.

TL;DR; - If you have data that needs to be passed like in the OP's case, set it using public properties on the destination, and then in viewDidLoad of the destination controller, load that data into the view's subviews.

Edit:

Similar question here - IBOutlet is nil inside custom UIView (Using STORYBOARD)

You may also want to utilize viewDidLayoutSubviews: for any subview manipulation.

like image 133
Matt S. Avatar answered Dec 06 '22 23:12

Matt S.