Why is my object not passing correctly through segue?

Let's say I have 2 controllers, BarViewController and FooViewController.

FooViewController has an output to UIImageView named imageView:

@property (nonatomic, weak) UIImageView *imageView; 

BarViewController has an output to the UIButton button. The BarViewController has a transition from this button to a FooViewController called BarToFooSegue (made in the storyboard).

When I run the following code and call NSLog on FooViewController.imageView.image, the result is zero and my image will not be displayed. Why is this so?

 // 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 tried setting FooViewController.imageView to strong rather than weak, but the problem remains:

 @property (nonatomic, strong) UIImageView *imageView; 

Starting my debugger, I noticed that the imageView in the FooViewController was correctly updated inside prepareForSegue: but then it again updates a few lines to some recently selected imageView with the @property image set to nil. I am not sure which part of the control flow causes this because it happened in lines written in assembler.

I got my code by adding the UIImage property to the FooViewController:

 @property (nonatomic, strong) UIImage *myImage; 

and change prepareForSegue: in the BarViewController to transfer the image instead of 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 viewWillAppear modification: in FooViewController:

 - (void)viewWillAppear:(BOOL)animated{ [self.imageView setImage:self.myImage]; } 
+4
source share
4 answers

Call [segue.destinationViewController view]; before setting the image, this will load the hierarchy of views and your outputs will be set.

+6
source

In prepareForSegue outputs are not yet defined - they are zero. You send a message to nil, which is excellent and therefore does not give you an error, but in this case it may lead to unexpected behavior. You can solve this by creating a temporary UIImage property and setting the image to that image in viewDidLoad or viewWillAppear.

+2
source

I agree with @ikuragames answer if you have to set imageView.image directly. But usually I keep the personal hierarchies of ViewControllers private.

I don't think it's ugly to add this UIImage property to Foo. I think this is actually prettier than @ikuragames the right solution.

+1
source
 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{  if([segue.identifier isEqualToString:@"BarToFooSegue"]){    NSURL *photoUrl = @"http://www.randurl.com/someImage";    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]]; FooViewController *vc = [segue destinationViewController]; vc.myImage = image; } } 
-1
source

Source: https://habr.com/ru/post/1434526/


All Articles