views:

970

answers:

2

I'm trying to grope my way through Obj-C to build an iPhone game.

I'd like to build an array of objects for later use. Here's what I tried:

NSMutableArray   *positionIcons;
[positionIcons insertObject:annotation atIndex:0];
positionIcons = [NSArray arrayWithObjects:annotation, nil];

The insertObject line leaves the count at 0. However, the next line correctly inserts the object (and count moves to 1). What gives?

+2  A: 

You need to initialize positionIcons, change the code to:

NSMutableArray *positionIcons = [[NSMutableArray alloc] init];
[positionIcons insertObject:annotation atIndex:0];
positionIcons = [NSArray arrayWithObjects:annotation, nil];
notnoop
wow - quick and perfect. I've been tearing my hair out.
BankStrong
+1  A: 

@msaeed has the right answer, but it's worth taking a little more time on that code fragment, because it leaks memory.

The iPhone doesn't support garbage collection, so it's important to understand how Objective-C's semi-automatic memory management works. Apple has a good reference here, but the gist of it is that you are responsible for maintaining the "retain count" of your objects. When initializing an object with an -init instance method (such as [[NSMutableArray alloc] init] in your example, but also any other method starting with "init", like [[NSMutableArray alloc] initWithCapacity:42], the newly-initialized object has a retain count of 1. Subsequent calls to that instance's -retain method increment the retain count, while calls to the instance's -release method decrement the count. When the count reaches 0, the object is deallocated, and further attempts to send it messages will result in null pointer exceptions.

In the case of @msaeed's corrected code, here's what's happening, by line:

  1. A new instance of NSMutableArray is allocated; the -init method is called, which initializes the instance and sets the retain count to 1. The positionIcons pointer is then set to the address of this new instance.
  2. The -insertObject:atIndex: method is called on positionIcons, and all is well (also, by convention adding an object to a collection like NSMutableArray increments that object's retain count, the idea being that the collection now has, in some sense, "ownership" of that object, and doesn't want it to be deallocated from underneath it).
  3. A new instance of NSArray is allocated, and the positionIcons pointer is then set to the address of that new instance. Because the retain count of the NSMutableArray from line one is still 1, it will not be deallocated, and since you've lost your reference to it, you can never call -release on it to clear it out of memory. There's your leak.

By convention, there's a difference in how you manage objects that are initialized with -init instance methods versus class methods like +arrayWithObjects: (in the first case, you have to release the object yourself, but in the second case, the object has already been sent an -autorelease message and will be deallocated on the next pass through the program's runloop unless you call -retain on it.

zbrimhall
thanks - the memory leak issue was in my code (and I'm sure msaeed didn't want to confuse by fixing simultaneously). I'm knowingly leaking memory all over as I learn obj-C. I plan to go back after I have more knowledge to sweep after myself. Your example is great for that.
BankStrong