0

I've been reading some tutorials on raywenderlich.com, and came across this block of code...

_players = [NSMutableArray arrayWithCapacity:20];

Player *player = [[Player alloc] init];
player.name = @"Bill Evans";
player.game = @"Tic-Tac-Toe";
player.rating = 4;
[_players addObject:player];

player = [[Player alloc] init];
player.name = @"Oscar Peterson";
player.game = @"Spin the Bottle";
player.rating = 5;
[_players addObject:player];

player = [[Player alloc] init];
player.name = @"Dave Brubeck";
player.game = @"Texas Hold’em Poker";
player.rating = 2;
[_players addObject:player];

Even if the project is using ARC, isn't this bad code? Re-allocating and initialing the variable? Shouldn't it be allocated once and then reference a method within the class that prepares the variable for reuse by wiping the existing data?

1
  • 1
    What do you think is wrong with that code? There is absolutely nothing wrong with reusing the player variable if that is what you are asking about. Commented Apr 30, 2014 at 18:07

3 Answers 3

2

It's okay. player is just a memory location where pointers to Player objects are kept. It can point to many, many Player's, one at a time.

Some referee might throw the "cuteness" flag, saying that a variable should be used for only one semantic purpose in any given scope. I'd argue in response that the purpose of the player variable is to hold new Player's while they get configured, before they are more permanently stored. It's the same argument that let's us say

for (int i=0; i<MAX; ++i)

without objecting that i wrongly assumes many values while it's in scope. That's not a problem with i, that's it's purpose.

Sign up to request clarification or add additional context in comments.

3 Comments

Very cool. I wouldn't assume the site would post something incorrect ;) but thought I'd ask about it. Thanks!
That's what he says: "..one at a time."
Oops. I misread that as "at one time" for some reason. Never mind. :)
1

You are thinking that when you call NSMutableArray:addObject it creates a new object that is a copy of Player and places that new object into the array?

If it did then your comment: ".. allocated once and then reference a method within the class that prepares the variable for reuse by wiping the existing data" would work.

But addObject doesn't do that, it adds a reference to Player object to the array and increments the retain count. So if you did what you said the result would be an array that contains multiple references to the same object. And if you iterated through the array and printed the values they would all come out identical. The reason is that the array would contain multiple references to the same object, when what you want is unique references to different objects.

When people take about the object being added to the array (and even the Apple documentation makes this mistake) that is not literally correct. It is not the object itself that is added to the array but a reference to it. That's a very very important difference and the Apple documentation should be scolded for being so misleading, as must everybody who uses sloppy and imprecise terminology when talking about "adding" an object to the array.

If you come from a C/C++ or similar background think of NSMutableArray as being an array of pointers not an array of objects.

Comments

0

Danh's answer is quite good.

To build on it, think of a local variable like "player" as a parking space. It can contain nothing (nil), or a car.

You can park a car in the space, do some work on the car, and then move the car somewhere else. Then you can drive a different car into the space, do some work on that car, and then drive it somewhere else.

The local variable player is a pointer, to an object of type Player. It starts out as nil.

When you execute the code player = [[Player alloc] init];, the system allocates memory for a new Player object, initializes it, and saves the address of that object in the player variable. The code then configures the newly-created Player object, then saves it to a mutable array. The array holds a strong reference to the new object.

Now, when you execute the statement player = [[Player alloc] init]; again, the system creates a completely new Player object, initializes it, and saves a pointer to that NEW Player object in the player local variable. The old value that was in player is overwritten, but that's ok, because the previous Player object has been saved to the _players array.

2 Comments

"the previous Player object has been saved to the _players array.". Isn't it the case that its not the object itself that is saved to the array, but a reference to it. If the object itself was saved to the array that would imply the array code has made a copy and thus when the op says about re-using the object would be ok (ignoring shallow versus deep issues). However that's not the situation.
@Sausages, yes. When you save something to a container like an array, all you are really saving is a pointer to the object. With ARC, the array saves a STRONG reference to the object, which causes the object to stick around in memory and not be deallocated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.