Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

johnnyjibbs

macrumors 68030
Original poster
Sep 18, 2003
2,964
122
London, UK
Hi all,

My first iPhone app is almost ready to ship, just a bit more bug fixing and a little bit of tax admin to finish off.

I know that this has probably been done to death but my main problem in completing development seems to be my app's memory usage. When I use instruments, I seem to have leaks here and there and eventually my app tends to crash. At the moment, it crashes too often and I can't seem to stem the problem. The app is a productivity app based on UIKit, so it's not as if it's an intensive game or anything. Plus, none of my table views generally get above 20-30 rows.

I do use UIImage's imageNamed: method quite a bit, which I've heard rumours that it has a leak in it. Can anyone confirm that? Is there an easy alternative to use instead?

I'm pretty sure I've released everything that I've alloc'd, retained or copied in my code but I think this is still an issue.

My other question relates to the didReceiveMemoryWarning methods. Currently, I've not implemented anything on my app delegate or any of my view controllers because I'm not sure how to use it. However, i've inserted an alert view that pops up whenever the app delegate method is called and I get it quite often. Does anyone know how many times your app is allowed to receive this before it crashes? I'm not quite sure how I can release memory at these points.

Any comments or pointers would be appreciated.

Thanks
John
 

jnic

macrumors 6502a
Oct 24, 2008
567
0
Cambridge
Leaks is crap, try Clang:

http://clang.llvm.org/StaticAnalysis.html

It's a static analyzer but a very good one. To run against your build, something like:

Code:
xcodebuild clean && ~/Desktop/checker-*/scan-build -analyze-headers -v -v -V xcodebuild -sdk iphoneos2.2

(modify as appropriate). It picks up the vast majority of memory leaks as well as other potential bugs.

Someone's also ported Valgrind, which is a bit more hassle to set up but will cover everything:

http://www.sealiesoftware.com/valgrind/

Enjoy!
 

jnic

macrumors 6502a
Oct 24, 2008
567
0
Cambridge

caveman_uk

Guest
Feb 17, 2003
2,390
1
Hitchin, Herts, UK
My other question relates to the didReceiveMemoryWarning methods. Currently, I've not implemented anything on my app delegate or any of my view controllers because I'm not sure how to use it. However, i've inserted an alert view that pops up whenever the app delegate method is called and I get it quite often. Does anyone know how many times your app is allowed to receive this before it crashes? I'm not quite sure how I can release memory at these points.
Do you have any in memory models you can get rid of when you get the message? In the app I'm working on now I ended up using singletons for the models that represent files that are stored on disk. When I get the message I tell all the singletons to flush their data representations to disk and then free that memory.

I think the message is pretty much a warning - 'you are using too much memory and do something about it'. If you do something about reducing your footprint then great. If you don't... well you were warned.
 

jnic

macrumors 6502a
Oct 24, 2008
567
0
Cambridge
(Apologies for multiple posts, tackling as separate questions.)

My other question relates to the didReceiveMemoryWarning methods. Currently, I've not implemented anything on my app delegate or any of my view controllers because I'm not sure how to use it.

https://developer.apple.com/iphone/...nstm/UIViewController/didReceiveMemoryWarning

didReceiveMemoryWarning will fire when you're running low on memory to allow you to release any you don't need in order to prevent running out. Any views you're not currently viewing will then be unloaded to save memory. After this, if there is still not enough free memory, your app will be killed.

Does anyone know how many times your app is allowed to receive this before it crashes?

It won't crash for as long as it can free enough memory to keep working. The first call that can't manage this will kill your app.
 

johnnyjibbs

macrumors 68030
Original poster
Sep 18, 2003
2,964
122
London, UK
UIImage imageNamed: is evil!

Thanks for your help. I now understand how the memory warnings work. It turns out that the culprit was in fact UIImage's imageNamed method. The caching behaviour is what I want, as I have a few images that are used on every table view cell.

However, it appears that there are two major bugs in the imageNamed method which can cause an app with relatively few images to run into major and terminal memory problems.

1) imageNamed seems to cache all images used for the duration of the app with no manual ability to control or empty the cache. This means that even if you have released an image and even the view and view controller that contains it, it will still hang on to the image in memory indefinitely, even in low memory situations.

However, it gets worse:

2) it appears to keep adding images to its cache, even when all images have been loaded, such that memory usage goes up and up and up.

I found that my memory problems all disappeared after I converted all imageNamed calls to initWithContentsOfFile:. However, that method doesn't cache the images and, despite having no memory problems from then on, my table view scrolling was unacceptably slow (predictably).

The solution was to implement my own image caching system, which is based on some code in this brilliant article.

Basically, I created a simple method in my app delegate called cacheImage: (NSString *)filename, which looks in an NSMutableDictionary called imageCache (initialised in the applicationDidFinishLaunching and set with an arbitary capacity - I found that 20 worked well for my app but it may depend on the amount of/size of images you have) to see if the image has already been cached and return that, otherwise initWithContentsOfFile and add to the dictionary. The keys are the filenames. To call it just replace all imageNamed calls with [appDelegate cacheImage:mad:"filename"]

The best bit about the above is that you can then empty this cache at any time in the applicationDidReceiveMemoryWarning method simply by calling [imageCache removeAllObjects] and the cache empties. Works like a charm.

On another note I noticed that the view controllers only release their views in low memory conditions if the loadView method is implemented. I haven't done this but may no longer need to since the above modification fixes all my crashes and improves performance massively.

jnic - I'm going to give that a go as it sounds good from what I've read.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.