My app uses 95MB of ram, when I made investigation by instruments I found out that CoreUI Image Date uses 70MB, how to reduce that usage?
There are a few considerations:
The only image objects that should be instantiated are those that are currently on screen. Do not hold the images in an array. (You might use a cache for performance reasons, but purge that cache upon memory pressure.) Sure, have an array of image file names (or identifiers or what have you), but not of the images, themselves.
For example, you want to ensure that you dynamically instantiate the images as they're needed (e.g. as they scroll into view) and release them when they are longer visible (e.g. as they scroll out of view).
If the dimensions of the images exceed the dimensions of the image views (adjusted for the scale of the display), these images should be resized to match. The amount of memory consumed is a function of the dimensions of the image, not of the image view. For example, a 100x100 image will take 40kb, but a 1000x1000 image will take 4mb.
These two points are relevant because images often require far more memory than might be suggested by the file size of the original assets. The runtime memory usage is a function of the image dimensions, not the file size of the assets. Image files are generally compressed, but are uncompressed when used by the app. The memory used at runtime is often 4 times width times height of the image, which will greatly exceed the amount of space used by the original JPG or PNG file.
Related
I'm trying to come up with some kind of standard to determine a maximum zoom setting for a given imageview (using a UIScrollView). In the apple docs it says that you should not initialize a uiimage object that is anymore than 1024 x 1024 into memory. Does it make sense to also apply this rule to a zoomed image, like for instance would it be best for me to make sure that the longest side of my image isn't zoomed any larger than x1024? Does anyone have any insight on this, I don't know too much about the memory requirements of ios and haven't been able to find anything from Apple (aside from the uimage requirements I stated).
You are really talking about two different things. Loading an image into memory takes up memory space so a picture that is 1024 x 1024 when loaded will always occupy that space in memory.
Zoom is something totally different. When you zoom, you arent adding any extra data to the image, you are simply taking the loaded image (lets say 1024 x 1024) and 'stretching' the bits across the screen.
The amount of data being stored doesnt change, the renderer just does different things with it i.e strectching out the pixels. With this being the case, I can only assume that you can set the max zoom to anything you want, but obviously the more you zoom in the worse the image will look.
Let's say I have a UIImage 1000x1000 and I have a UIImageView with a frame size of 50x50. If I set my UIImageView's image as the large image, is the UIImage automatically resized to 50x50? The UIImageView contentMode is ScaleToFit.
I know that the image does shrink down to 50x50 to fit in there, but in terms of memory, would it be better that I resized the image to 50x50 before setting it as the UIImageView image?
I know it won't make a difference for one image, but I have hundreds of large images and image views in a UIScrollView, so I want to make sure I get the fastest and smoothest performance.
I can think of a couple considerations. UIImage ImageNamed: will cache the image for the entire app run, even when no longer used. If arbitrary images will be used or added as opposed to a static set, make sure to load the image with NSData from a connection, file, or database. Also, I haven't checked in instruments for at least several iOS versions, but I believe that the original image is cached for scaling. If there is no specific issue that you actually run into with running out of memory or slowness, don't bother with pre-emptive optimization. Otherwise, there are some techniques that may help. First, you may only want to retain what is currently on screen. This is easier to do with a UITableView and cell reuse than with a bare UIScrollView. Second, for one app I used that held a lot of thumbnails, I scaled them once and stored them in the database.
The restriction of 1024x1024 as the largest image for an iPhone is a problem with iPhone 4. However if an #2x image is used with maximum dimensions of 2048x2048 everything looks equally good on the 4 as it does on a 3 - tried and tested in simulator and device. Question is, does the image dimension restriction relate to the UIImage or the resource that it contains? I can't imagine resources of more than 1024 pixels are discouraged with the 960 pixel height of the screen.
The right answer is really to use tiles so that things look even better, but the deadline for for this deliverable is too close - it's a future thing.
From UIImage class reference:
You should avoid creating UIImage
objects that are greater than 1024 x
1024 in size. Besides the large amount
of memory such an image would consume,
you may run into problems when using
the image as a texture in OpenGL ES or
when drawing the image to a view or
layer. This size restriction does not
apply if you are performing code-based
manipulations, such as resizing an
image larger than 1024 x 1024 pixels
by drawing it to a bitmap-backed
graphics context. In fact, you may
need to resize an image in this manner
(or break it into several smaller
images) in order to draw it to one of
your views.
That is, views are rendered and composited with the iPhone's GPU. If your view, for example, overrides drawRect and tries to render a very big UIImage you might run into problems. Newer generation iDevices, such as iPad and iPhone 4 support bigger textures than 1024x1024 (2048x2048 I think).
I didn't realise there was a restriction, I'm using an image 15198 × 252 as the scrolling landscape in Scramble... works really well, though I must say I did have reservations before I tried it out!
I have an application that let's users view images. The user decides what images to use, so the size can range from 10x10 to 10000000x10000000 (I am exeggerating). All is well up to a certain size, when the image is bigger than the iPhone's memory. Quite understandably.
But how do I fix it? Is there a way to load only a portion of the image (I'm using an CATiledLayer, so I could load/release tile by tile).
Thanks in advance!
Unless you have an uncompressed image format it would be very hard to load the image in patches, you will have to provide the patches that the user would load, determine what portion of the image to show, and load the correct patches. There is an example for this "ScrollViewSuite" that demonstrate that technique. But this technique does require a preprocessing step.
I'm writing a card game for the iPhone, and I'm not sure about the best strategy for displaying the cards. I have a basic prototype that creates a UIImageView that can be dragged for each card with a dummy image. I wanted to use one large UIImage that contains the faces of all of the cards, and then have each draggable UIImageView display a part of that image. I must be misunderstanding what setBounds is for - I thought that controlled which part of the underlying image is displayed. So, two questions:
Is this the right approach?
How do I display just a part of the image?
Depending on your resolution, this might not be the best approach.
From Apple:
You should avoid creating UIImage
objects that are greater than 1024 x
1024 in size. Besides the large amount
of memory such an image would consume,
you may run into problems when using
the image as a texture in OpenGL ES or
when drawing the image to a view or
layer. This size restriction does not
apply if you are performing code-based
manipulations, such as resizing an
image larger than 1024 x 1024 pixels
by drawing it to a bitmap-backed
graphics context. In fact, you may
need to resize an image in this manner
(or break it into several smaller
images) in order to draw it to one of
your views.
Now, you are talking about breaking it up into several smaller pieces, but given UIIMage's caching, I am not sure what happens to memory every time you access the image and copy a sub-rect out of it. I think the approach I would take is to have an array of images, instead of one big one.