1

I have a complex App that runs reliably, but I'm puzzled why I need to retain a particular NSArray ('sources') twice to prevent a crash (although no exception is reported on the console, but the application crashes and returns to the springboard).

A snippet of the code is included below. There's too much code to paste it all, but you have my word that there are no explicit calls to release the array. 'sources' is an instance variable.

If I only retain the array once (or not at all), I get the crash. With two retains, the App is perfectly stable.

NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"Sources" ofType:@"plist"];

sources  = [[NSArray arrayWithContentsOfFile:plistPath] autorelease];

[sources retain];
[sources retain];

Thoughts on why I would need to retain this array twice appreciated. Thanks in advance.

Snips
  • 6,575
  • 7
  • 40
  • 64

6 Answers6

10

You’re using +arrayWithContentsOfFile:, which returns an autoreleased object, then autoreleasing it again. Take out the call to -autorelease and you’ll be OK. You could re-write it as so:

sources  = [[NSArray arrayWithContentsOfFile:plistPath] retain];
Jeff Kelley
  • 19,021
  • 6
  • 70
  • 80
  • 1
    This is correct. For more info, see this question on memory management: http://stackoverflow.com/questions/370427/learn-obj-c-memory-management – Jay Peyer Nov 03 '10 at 02:21
7

There is an explicit call to release the array. autorelease is just as explicit as release — it just happens later. Not only that, but it was wrong to autorelease the array in the first place, since you didn't own it. One retain is necessary to claim ownership of the array. The second one prevents the crash by balancing out the incorrect use of autorelease.

Chuck
  • 234,037
  • 30
  • 302
  • 389
3

Is it something to do with that autorelease? I can't see why that's there: it should be the factory method that autoreleases. Although I don't know what the consequence of adding an extra autorelease is, it might be worth seeing what happens if you take that out along with one of the retains.

Cris
  • 1,939
  • 3
  • 23
  • 37
  • Autorelease is clearly incorrect, but anyone know why precisely it causes a problem? I would have thought once the nearest autorelease pool knows about the array, it would send a single release when being drained, however often autorelease was sent. Clearly not, but anyone know why? – Cris Nov 03 '10 at 00:29
3

Ditch the autorelease on the factory method. It's why you need a second retain.

drekka
  • 20,957
  • 14
  • 79
  • 135
2

That's because arrayWithContentsOfFile: returns an autoreleased array to you. Calling autorelease on this array will release it twice at the end of current event run loop.

koo
  • 2,888
  • 1
  • 23
  • 29
1
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"Sources" ofType:@"plist"];

sources  = [[NSArray alloc] initWithContentsOfFile:plistPath];
EdChum
  • 376,765
  • 198
  • 813
  • 562
cncool
  • 11
  • 1