pmk
pmk

Reputation: 1897

Reduce Memory Usage

So I am developing an iOS app that basically does the following: On iPhone it is a UITabBarController with five tabs, on the iPad I have a UISplitViewController with a MKMapView on the right hand side and a UITabBarController with four tabs on the left. The app uses ARC.

Let's say we are talking about sights.
Depending on the current city the user is in, my app downloads all sights for this city to the device. Once a certain sight has been downloaded, it is stored in my local db so the user does not have to download it again. If the user searches for another city, all sights for this city will be downloaded. And so on. All saved sights will be listed inside a tableView or on a mapView, sorted by their city.

A sight consists of:

The app allows the user to create new sights, take pictures for it, fill in its meta info and upload it to my webserver.

All this is working fine as long as only a small number of sights has been downloaded. With 40+ sights locally saved I receive memory warnings and the app quits. The problem is that the app is meant to browse a very huge number of sights, a few hundred.

Now I would like to know some techniques to handle such memory issues.

I guess my problem is that with the start of my app, all locally saved sights are being loaded in an array as the datasource for the tableView or the mapView. But since I want to display them I see no other way than doing so.

How do other applications deal with a huge number of custom objects consisting of multiple images and a number of meta information or similar? Does some kind of best practice for handling this kind of problem exist?

Thank you very much in advance!

Upvotes: 1

Views: 983

Answers (3)

A'sa Dickens
A'sa Dickens

Reputation: 2085

The way I handled using a ton of images was by using

https://github.com/rs/SDWebImage

It caches images, downloads them, and dumps cache all on a separate thread for you so you don't have to consider that stuff.

Upvotes: 2

Rob
Rob

Reputation: 438232

The key concept is that you should not load all of your images into an array/dictionary. At the very most most, you should only load references to those images (e.g. if the images are in the Documents folder, just load the path/URL of the image). Then your UI should create the UIImage for those images it needs to present the UI at any given point.

If you're using a table view or collection view, iOS handles this very gracefully, calling your data source's cellForRowAtIndexPath and only at that time should you create the UIImage. And when the cell scrolls off, if you're following the typical cellForRowAtIndexPath implementation, that cell we be reused for another row in the table, you'll reassign the image of the cell with a new UIImage, and given that the old image presumably doesn't have any more strong references, it will be released and the memory taken by the image will freed.

A couple of additional thoughts:

  1. You say that information is downloaded into your local database. Are you downloading URLs for images, or are you actually putting the images, themselves, into the database. In my experience, if you're dealing with anything other than very small thumbnails, you don't want to save the image in the database itself (as the iOS database is pretty inefficient in terms of saving large blobs) and you'll see a performance hit. If the images are, say, larger than 100kb each, you might want to download the images to your documents folder, and only store the file URL/path for the image in your database.

  2. If you app is showing lots of images at one time (e.g. iPad app and you have a photo thumbnail browser that can show, say more than 20 images at a time), you might want to make sure the image that you're loading in your UI is sized appropriately. For example, while iOS can gracefully take high-resolution images and show you a thumbnail by having a small UIImageView with UIViewContentModeAspectFill, that can be an extravagent use of memory. I use an image resizing algorithm whereby I'll resize images to the appropriate size for my UI, saving memory. You only really need to worry about this if your images are huge or if you're showing lots of thumbnails simultaneously.

  3. Once you change your app to load images into UIImage objects on the fly, you may become sensitive to additional performance considerations you might not have experienced thus far. The typical solution is to use caching, whereby you keep images you've recently loaded in a NSCache object, but that cache will be automatically emptied if the device runs low on memory. So it's the best of both worlds; the performance that you're used to experiencing when you loaded all of your images in at one time, but with greater sensitivity to gracefully handling low memory situation. By the way, third-party classes like SDWebImage do this caching for you automatically.

Upvotes: 3

ggrana
ggrana

Reputation: 2345

You must load only some info of the data that you want to show, for example ID, title, that you will use to populate initial information, and the rest of the info, like images, you will need to load at the background, and update when they are ready, you can take a look at this answers for example:

UICollectionView scrolling is slow

Also you must to take care that you will not stay with all the infos when your data is not showing on the screen.

Upvotes: 1

Related Questions