McDJ
McDJ

Reputation: 807

iPhone memory management, making my app crashproof for multiple devices

I'm developing an app which uses a UIScrollView to show a list of images based on search criteria. Using a button the user can load more images.

When testing on an iPhone 4 the ViewController receives a memory-warning at ~750 images. When testing on an iPod 2nd generation a memory warning is received at ~150 images.

My understanding is that when didReceiveMemoryWarning is called, one can free memory by releasing objects but recovery from low memory is not guaranteed.

I've implemented didReceiveMemoryWarning and release basically all objects. In instruments I see memory usage drop back to ~3MB. The first time the iPod reaches its memory limit all goes well, memory is released and the app resumes normal operation. The second time however, when didReceiveMemoryWarning is called, I can see the objects released, but the app crashes anyway.

So, how do I make my app crash proof? I want to make sure that all devices running the app can load as much images as memory allows but I also want to make sure that the app doesn't crash.

I would prefer the app never to reach didReceiveMemoryWarning and set a limit to the number of images that can be displayed, but how can I determine how many images each possible device should be able to load?

Furthermore, the size of the images is not guaranteed. While testing I come to this arbitrary number of 150 on an iPod, but what if the images on the server at some point in time are twice as big? Then the app would probably crash at 75 images.

Any sugestions?

Upvotes: 2

Views: 610

Answers (2)

jer
jer

Reputation: 20236

First off, what you probably want to do is not display all your images all at once. You rather, probably only want to disable the images that are currently visible, plus a few that are off screen preloaded for when the user scrolls to that location.

This is much the same way as the photos app works, how UITableView is implemented. Basically it boils down to this:

You have your main scrollview, and inside it, you have individual cells. These cells are small views that are added as subviews to your scrollview at specific offsets. You then add your images to these cells.

When a user scrolls the scrollview, you first ask the scrollview to dequeue a new cell for you, much the same way you'd ask a table view to dequeue a cell for you to use. This saves the cost of an allocation, if one has been recycled. If you cannot dequeue one from a recycled set, then what you have to do is quite simple: allocate one as you are doing currently.

Furthermore, to implement this cell recycling, what you need to do is see which cells are visible on screen. If one or more cells go off screen, you add them to the recycled cells NSSet which you create. This set just holds cells for later recycling. There's some sample code Apple has which demonstrates this, and it's called PhotoScroller. It also is demonstrated in a WWDC10 video, session 104. I suggest you watch it. Ignore the parts about tiling, you don't need to know that for your purpose.

Once you have this in place, this will force you to set up your cells only when they're needed, which is also another key aspect of this behaviour.

Finally, when you do receive a memory warning, just drop the recycled cells set. If you ever get high enough that this matters, that is, you'll save a few megs of memory. :) (Do not forget to implement it though, ever, when you hold onto temporary data that you don't specifically need around...cells which are not visible on the screen are a good example of this, as are caches.)

Upvotes: 1

Steve
Steve

Reputation: 1199

You should lazy load your images and only load the images you need at that time. Your app can't show all those images on one screen anyways, so on your scrollview you should only load those images that can fit on the screen and maybe a few around that, and as the user scrolls to release the images it no longer needs.

Upvotes: 0

Related Questions