UIImageView image does not update visibly when image property is set
Asked Answered
R

2

3

I have a UIImageView whose user interaction is true and to which I have given a tap gesture recognizer, whose action handler is as follows:

@IBAction func tap(_ sender:UITapGestureRecognizer) {
    let iv = sender.view as! UIImageView
    let im = iv.image!
    let im2 = UIGraphicsImageRenderer(size:im.size).image { _ in
        UIColor.red.setFill()
        UIBezierPath(rect: CGRect(origin:.zero, size:im.size)).fill()
    }
    iv.image = im2
}

I expect the image displayed, when I tap the image view, to be replaced by a solid red image. This works fine on my High Sierra machine running Xcode 9.4. But on my Sierra MacBook running Xcode 9.2, nothing visibly happens.

It's weird. By pausing in the debugger, I can see that the new image is being constructed correctly:

enter image description here

The image is being replaced, but the image view isn't being redrawn. Adding calls like setNeedsDisplay does nothing.

Moreover, if I then proceed to replace the image view's image with a different image, I see the red image!

    iv.image = im2
    delay(0.5) {
        iv.image = im // causes im2 to appear!
    }

Some sort of behind-the-scenes caching is evidently causing the image view to get behind in its display by one image.

Can anyone shed light on this? It's presumably a bug in iOS itself, and perhaps in 9.2 specifically; how would one work around it? (Obviously one could substitute another image view wholesale, but that wouldn't tell us what's going on with the caching.)

Rosanne answered 10/6, 2018 at 18:52 Comment(5)
I suppose the code runs from a UIViewController. Can't you just add a property and refer the imageView directly with it from within the tap handler? I mean that I won't use sender.view to refer the ImageView.Eggett
This is probably a stretch but perhaps there is some "magic" going on with the UIGraphicsImageRenderer. Do you still have this issue if you create the red image using other techniques such as the good old UIGraphicsBeginImageContextWithOptions and UIGraphicsGetImageFromCurrentImageContext?Macswan
@Macswan I don't know that it's a stretch at all; I had the same idea. I'll try it...Rosanne
@Macswan No, it doesn't change anything. I think the "magic" must be in the image view itself (maybe combined with the fact that the image is being generated in real time, but then how do we explain the fact that the generated image is visible in the debugger?).Rosanne
@lookaji No, changing how the image view is referred to changes nothing.Rosanne
R
2

This seems to be a workaround:

iv.image = im2
delay(0.05) {
    iv.image = nil
    iv.image = im2
}

But what a horror... Omitting any of those assignments, or reducing the delay to zero (e.g. by calling DispatchQueue.main.async instead), causes the workaround to fail.

Rosanne answered 10/6, 2018 at 19:24 Comment(1)
Moreover, I haven't explained anything, even though I now have code that "works".Rosanne
A
0

Encountered this problem in Xcode 13. Set the contentModel to center in the xib file

or

iv.contentMode = .center
Agility answered 28/2, 2022 at 7:15 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Trilingual
this works for me, change the contentMode of the UIImageView to .centerBans

© 2022 - 2024 — McMap. All rights reserved.