0

I have a universal game written in Swift with about 200 images, which take up around 200 MB of ram. However, on storage they take up only 15MB. On Xcode the size of the default view is 600x600, and the view that my UIImageView is residing in is 200x200. My goals is to have an image that uses the least amount of ram, and uses the least amount of storage space, but retains its quality.

For the ram: Should I run some code to resize the image prior to displaying it in order to use less memory, which I worry may be slightly CPU intensive.

For the storage space: Is there a way I can calculate the image dimensions I would need in order to satisfy all iOS devices?

Or am I looking at this completely the wrong way.

Dima
  • 23,484
  • 6
  • 56
  • 83
james
  • 353
  • 3
  • 16
  • 1. doesn't iOS solve that for you if you use xassets? to only publish the assets for the device that is downloading – morksinaanab Oct 19 '16 at 17:11
  • 2. you can always run pngquant on (png) images to reduce filesize: https://pngquant.org – morksinaanab Oct 19 '16 at 17:12
  • 3. could you use some sort of sprite solution, where you merge all the images in 1 image, but show part of it? – morksinaanab Oct 19 '16 at 17:13
  • In iOS9, Apple introduced a bunch of new ways of reducing application size and called them "App Thinning". One of this is, if you use Asset Catalogs, you can target images, textures and sprites to device types (there is a couple of ways to do that). For each device, Apple sends only the necessary variants – that should take care of the image sizes. – Baglan Oct 19 '16 at 17:14
  • 1. I believe you can't use xassets when using contentsOfFile. – james Oct 19 '16 at 17:16
  • 2. Never heard of pngquant, I'll give it a try thanks – james Oct 19 '16 at 17:17
  • 3. Can sprite solutions only be used with spritekit? And not normal UIViews? – james Oct 19 '16 at 17:18
  • So the size of an image view corresponds to the required dimensions of the image I need to supply? I thought the sizes of image views were just arbitrary numbers. And if I only supply a 1x it will be up sampled for the devices seeking higher resolution images? – james Oct 19 '16 at 17:34
  • Using pngquant it only going to reduce the on disk size. If you want to reduce the amount of runtime memory consumed by image rendering it can be done in SpriteKit with this Framework: http://stackoverflow.com/a/38679128/763355 – MoDJ Oct 19 '16 at 20:41

1 Answers1

2

The assets catalog is going to be the most efficient way to have different assets for different devices, while enjoying "app thinning" which can allow a device to only download the assets needed for that particular device (keeping app downloads as small as possible).

For example, if you have a 200x200 image view, if you want to be most memory efficient for different types of devices, you'd have a 1x (i.e. 200x200), 2x (i.e. 400x400), and 3x (i.e. 600x600) rendition of that asset, and through the efficiency of assets catalogs, the device would download and use the asset of the appropriate scale for that device.

If, on the other hand, you only supply only a 1x image (e.g. a 200x200 image in our above example), it will look pixelated on a retina device, which will put off many users. Or you can supply only a 3x image (e.g. a 600x600 image), it will look sharp on all devices, but you'll be taking up more memory than needed on non-retina devices (or, if you do just-in-time resizing, you can offset the memory impact, but at the cost of performance).

So, if you want the best looking and most responsive UI that works on well on devices of multiple scale resolution, you'd supply all three resolutions. And if you use an asset catalog, it makes the selection of the asset at runtime easier, and you open up the possibility of app thinning.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I'll use that method. However, just to confirm, regardless of the size of the image file, the memory usage will only depend on its dimensions? And when using UIImage(named: ""), when does iOS release the cached image? – james Oct 19 '16 at 20:21
  • Memory usage is dictated by the dimensions of the image, not by the dimensions of the image view in which it's used. And regardless of the size of the asset (which is generally compressed in the form of a PNG or JPG), when you use the image, it's uncompressed, generally requiring four bytes per pixel (e.g. 4 x width x height). – Rob Oct 19 '16 at 20:43
  • Regarding the freeing of the memory, when you use `UIImage(named:)`, the image is cached. But that image cache responds to memory pressure, so as long as you set your strong references to `nil` (not `UIImage(named: "")`), you won't see the memory released immediately, but when the memory is needed (i.e. there is a memory warning), the cache will release its strong references. – Rob Oct 19 '16 at 20:43
  • Images cached with this UIImage method do not get released at any specific time. They might be released when new images are loaded and they would be released in a low memory warning situation. But, you cannot control the caching via this API. You also will not see any runtime memory use reduction, these app slicing approaches just choose a different source image depending on the device that it running the code. – MoDJ Oct 19 '16 at 20:44
  • Perfect thank you. This does seem to be the best way. – james Oct 19 '16 at 20:51