Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my object not being passed correctly via segue?

Say I have 2 controllers, BarViewController and FooViewController.

FooViewController has an outlet to a UIImageView called imageView:

@property (nonatomic, weak) UIImageView *imageView;

BarViewController has an outlet to a UIButton button. BarViewController has a segue from this button to FooViewController, called BarToFooSegue (done in storyboard).

When I run the following code, and call NSLog on FooViewController.imageView.image, the result is nil, and my image won't display. Why is this the case?

// code in BarViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{

    if([segue.identifier isEqualToString:@"BarToFooSegue"]){
        NSURL *photoUrl = @"http://www.randurl.com/someImage"; // assume valid url
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]];
        UIImageView *imageView = [[UIImageView alloc] initWithImage:image];

        [segue.destinationViewController setImageView:imageView];
    }
}

I've tried setting FooViewController.imageView to strong instead of weak, but the problem remains:

@property (nonatomic, strong) UIImageView *imageView;

Running my debugger, I notice the imageView in FooViewController is updated correctly inside prepareForSegue: but then gets re-updated a few lines afterwards to some newly allocated imageView with @property image set to nil. I am not sure what part of the control flow is causing this because it happened in lines written in assembly language.

I got my code working by adding a UIImage property to FooViewController:

@property (nonatomic, strong) UIImage *myImage;

and changing prepareForSegue: in BarViewController to pass the image instead of the imageView:

// code in BarViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{

    if([segue.identifier isEqualToString:@"BarToFooSegue"]){
        NSURL *photoUrl = @"http://www.randurl.com/someImage"; // assume valid url
        UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]];

        [segue.destinationViewController setMyImage:image];
}

and modifying viewWillAppear: in FooViewController:

- (void)viewWillAppear:(BOOL)animated{
    [self.imageView setImage:self.myImage];
}
like image 743
Popcorn Avatar asked Feb 19 '23 03:02

Popcorn


2 Answers

Call [segue.destinationViewController view]; before you set the image, this will cause the view hierarchy to be loaded and your outlets will then be set.

like image 97
ikuramedia Avatar answered Mar 05 '23 08:03

ikuramedia


In prepareForSegue outlets aren't defined yet--they're nil. You're sending a message to nil, which is perfectly fine and therefore doesn't give you an error, but in this case it can lead to unexpected behavior. You can solve it by creating a temporary UIImage property, and set your image view to that image in viewDidLoad or viewWillAppear.

like image 27
Scott Berrevoets Avatar answered Mar 05 '23 09:03

Scott Berrevoets