-1

I have a scrollview containing multiple UIImageViews that are kept in an array. Each of these UIImageViews has the same background image, but a unique mask. When these images are not displayed on the screen, I want to remove the mask to save memory. A function like the following is called when the mask has to be created or deleted. In this case however, the memory footprint will not decrease when the imageView mask is set to nil.

func updateView(imageName: String, imageView: UIImageView, show: Bool)
    if show {
       let newMask = UIImageView()
       newMask.image = UIImage(named: imageName)
       newMask.frame = frame
       imageView.mask = newMask
    } else {
       imageView.mask = nil
    }
 }

How to solve this problem? As a beginner I've been looking for the answer for days and any help would be very much appreciated.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
willemdb
  • 3
  • 1
  • Is this a case of premature optimization? Do you know that the memory footprint is a problem right now? – NRitH Dec 04 '18 at 20:33
  • Either way, why not cache the masked images instead of instantiating them in `updateView()`? – NRitH Dec 04 '18 at 20:34
  • A tableview might be more appropriate for this use case. Are you displaying large list of images? – Alan Perez Dec 04 '18 at 20:56

2 Answers2

1

The largest object in your code is the UIImage that you are using as the image of the UIImageView that you are using as a mask. (The UIImageView itself is negligible.) UIImages loaded by saying UIImage(named:) are cached; therefore, removing the UIImageView doesn't cause memory to decrease. But the good news is that the next time you do this, the image is already cached, so memory won't increase either.

Note too that if the UIImage is large, its memory will be large, even if you are displaying it small (i.e. if you are making the UIImageView do the work of reducing the UIImage size to its own size). That is a huge waste of memory. There are standard techniques for loading or redrawing a UIImage at the actual size needed for display, which can save massively on memory.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Hi Matt, thanks for your answer! The problem is that the user needs to zoom in quite a bit (~16x), so all the ~200 mask images are high res (they are the quality required when fully zoomed in, to still have sharp borders). I'm currently thinking of having a low-res mask image when zoomed out and the full res only when zoomed it, and then not cache the high-res. To not cache I guess I need to use UIImage(contentsOfFile)? I haven't been able to find an example of how to use this with image assets though. As said I'm a beginner.. – willemdb Dec 05 '18 at 08:40
  • "I haven't been able to find an example of how to use this with image assets though" But that wasn't in your question. The problem of not caching an image taken from an asset catalog is an interesting problem, but its _not what you asked about_. If you ask the wrong question you will inevitably get the wrong answer. We can only answer the question you _do_ ask. This is called an "x-y" question. – matt Dec 05 '18 at 21:56
0

Note that the documentation for UIImage(named:) states that it does cache the images it loads. So unless you are getting a memory warning, unsetting the image is not going to reduce memory consumption; the image is still in the cache. Use one of the other initializes that don't cache, like init(data:) or init(contentsOfFile:) if you really don't want caching.

Josh Homann
  • 15,933
  • 3
  • 30
  • 33