planewalker
planewalker

Reputation: 298

In what method should I recreate resources after didReceiveMemoryWarning?

I have a view controller that has a private NSArray variable. The variable is initialised in the viewDidLoad method. A few questions arise for the case when the didReceiveMemoryWarning is called:

  1. Should I set the private variable to nil?
  2. If I set it to nil in what method must it be recreated? Does the view controller call the viewDidLoad method to recreate it?

I'm asking because other methods of the view need this variable and won't work if it's nil.

Thank you!

Upvotes: 8

Views: 488

Answers (5)

Andrea
Andrea

Reputation: 26385

Create custom getter that load data lazily. Something such as this snippet is good for non-mutithreading eviroment:

- (NSArray*) dataArray {
  if(_dataArray) return _dataArray;

  _dataArray = [self lordata];
  return _dataArray;
}

In this way data are always reloaded if you "release" them in memory warnings

Upvotes: 1

occulus
occulus

Reputation: 17014

Typically you unload a private property by assigning nil via the setter (e.g. self.propertyName = nil). Or you could set the ivar to nil after calling release, e.g. [_propertyName release]; _propertyName = nil;, but the former is preferable.

The didReceiveMemoryWarning method is called when there is a low memory situation. It is called on every view controller, including the one(s) responsible for the currently visible UI!

Therefore, you can't just unload data arbitrarily when you get a call to didReceiveMemoryWarning -- the view controller might need that data if it is currently visible on the display.

The general principle is that didReceiveMemoryWarning can get rid of any resources it can to assist freeing up memory, but only those that aren't immediately needed. For example, in an OpenGL game you wouldn't unload textures that are currently visible on the display. However, see my last paragraph.

Typically you reload the resources by checking they are loaded when you need them, and if not, loading them.

It's not worth niling/releasing tiny resources such as a single normally sized string. You should concentrate on items taking up significant amounts of memory.

Recent advances in behind the scenes memory management mean you're less likely to need to actually unload data these days - the operating system can unload and reload uncompressed image data and the like behind the scenes.

As Hot Licks mentions, the simulator has an option for simulating a memory warning. It's worth triggering this memory warning at various points in your app to see how it behaves.

Upvotes: 4

Hot Licks
Hot Licks

Reputation: 47699

As an example, I had an app that downloaded data to a very long table view (potentially 1000s of records). To support this I implemented a "sparse" array, allowing empty elements that would be "faulted in" over the net when referenced (with a "downloading" indicator in the table cell while downloading).

This was rigged so that when didReceiveMemoryWarning occurred the array would be purged, using a least-recently-used algorithm to delete the oldest N% of the array. Recovery would be automatic -- the emptied cells would reload when they were referenced.

Not that I recommend this specific scheme, but note the general features of having a lot of data, having a way to "prioritize" what should be deleted, and having a "soft" way to reload the data (ideally only reloading the parts that are needed in the near future).

Upvotes: 0

Jão
Jão

Reputation: 469

The ViewDidLoad method is called only once, when your ViewController is initialized. If you must reload some data to your NSArray, you should call your own methods to do that when needed.

If this array is used by various parts of the code, maybe you should think about redesigning your code structure to avoid a huge concentration of data inside only one object.

Edit: As pointed by @occulus in the comments below, it is not called when the View is initialized, but when the View is loaded by the ViewController.. my mistake

Upvotes: 0

Vignesh
Vignesh

Reputation: 10251

Its better to set your variable to nil. I mean release the memory it is holding in didReceiveMemoryWarning and set a dirty flag.

You can always check the dirty flag in array's getter(you can write your own) and repopulate it. It is probably not the best way. It entirely depends on the array's usage.

Upvotes: -2

Related Questions