0

I want the image in my UIImageView to us a different image file that's cropped to correctly fill the landscape mode upon the orientation changing from portrait to landscape. All of the following code is defined in a class that extends UIViewController.

The following function is definitely being called when the phone rotates because my printf function is printing to the output.

- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {

    [super traitCollectionDidChange: previousTraitCollection];
    if ((self.traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass)
        || (self.traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass)) {
        printf("Orientation Change!\n");
        UIImage * newImage = [UIImage imageNamed: @"landscape-image"];
        [self.imageView setImage:newImage];
    }
}

I defined the property imageView in my .h file as follows:

@property (nonatomic, nonnull, readonly) UIImageView * imageView;

And I initialize the imageView as follows:

UIImage * image = [UIImage imageNamed:@"portrait-image"];
UIImageView * _imageView = [[UIImageView alloc] initWithImage:image];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
[pageView addSubview:_imageView];

This does not work for me though. When I change the orientation, the imageView image stays the same and zooms in like it normally does. Since the traitCollectionDidChange function is being called when the phone rotates, I assume the issue must be with how I'm changing the image. I'm relatively new to iOS development so I could just be missing something important for updating UIImageViews. Any help is appreciated.

Michael
  • 835
  • 2
  • 10
  • 24

1 Answers1

1

When you create the imageView using UIImageView * _imageView = [[UIImageView alloc] initWithImage:image];, you are shadowing the automatically synthesised variable _imageView, with a new variable of the same name.

The newly created UIImageView instance is therefore not assigned to the imageView property. As a result, when the device is rotated and the second method is run, self.imageView is nil, and you call to [self.imageView setImage:newImage] does nothing.

To solve it, all you need to do replace UIImageView * _imageView = [[UIImageView alloc] initWithImage:image]; with _imageView = [[UIImageView alloc] initWithImage:image];

More on the messiness of automatically synthesised properties in Objective-C in this answer When should I use @synthesize explicitly?

EDIT --

In addition, the - (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection may be called at any time, and initially, so you want to detect the orientation in that method, and not just set the image to your landscape image.

(and on this - ou may want to re-evaluate your requirements regarding 'landscape' vs 'portrait' image because iOS apps can run in a variety of environment, iPad / iPhone / compact.. it is complicated. https://developer.apple.com/documentation/uikit/uitraitcollection)

To complete the answer, this should work on iPhone

- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {

    [super traitCollectionDidChange: previousTraitCollection];

    if ((self.traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass)
        || (self.traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass)) {

         if (self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
              [self.imageView setImage:[UIImage imageNamed: @"landscape-image"]];
         } else if (self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular
                    && self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
             [self.imageView setImage:[UIImage imageNamed: @"portrait-image"]];
         }
    }
}
patroclus974
  • 364
  • 1
  • 3
  • I made the suggested change, but it still isn't working. When I stepped through before adding the change, I noticed that the property was set to nil, and after adding the change it was set correctly. But even so, the image on my image view is still the same image. In the debugger under the `_storage>_imageAsset>_assetName` attribute, I see that once I step over the line where I overwrite the image, it changes to the new image name, but when I look at the view debugger, it still uses the old image on landscape mode. – Michael Feb 13 '19 at 01:39
  • Nevermind, it's definitely showing up in the view debugger. I just need to mess with it some more. – Michael Feb 13 '19 at 02:00