NSMutableArray add Object as pointer only?

TalkingCode picture TalkingCode · Mar 30, 2009 · Viewed 33.5k times · Source

I have this little code

 NSMutableArray *myArray = [[NSMutableArray alloc] init]; 
 NSNumber *myNumber = [NSNumber numberWithDouble:752.65];

 [myArray addObject:myNumber];

With this code I store Objects inside an array. But now I have two objects independent from each other.

If I change myNumber after it's been added to the array the value inside the array does not change. How can I archive that? I tried to give a pointer only to the array but it did not work.

Answer

Peter Hosey picture Peter Hosey · Mar 30, 2009

You cannot put a variable into an array, and that's what myNumber is: a variable. A variable is a container, and so is an array; the difference is that a variable is not also an object*, like the array is, and you can only put objects into an array.

What you pass to addObject: is not the variable myNumber, but the object it contains. That's what you are adding to the array.

To add the variable instead of the object inside it, you would need to do addObject:&myNumber, in order to pass a pointer to the variable itself. But this won't work, for two reasons:

  1. As I mentioned, the variable is not an object, and you can only add objects.
  2. Since this is a local variable, it will perish when the function exits; then you have a pointer to dead memory inside your array. When you go to access whatever's at that pointer, your program would crash.

There are three solutions that will work:

  1. As f3lix suggests, create a mutable number class, and create your number object from this class instead of NSNumber. You'll need to override all the primitive methods of NSValue as described in the NSNumber documentation.
  2. Replace the object in the array instead of mutating it. Of course, this requires having access to the array from everywhere you'd want to change the number.
  3. Create a model object class that has the number as a property.

That last solution is, in my opinion, the correct one. I doubt you are managing only a list of numbers; more likely, you are showing the user a list of something that has the number as a property. Model this in your code, and everything becomes much simpler.

Your code after replacing the bare NSNumbers with model objects will be something like:

MyModelObject *myModelObject = [[[MyModelObject alloc] init] autorelease];
[myModelObject setNumber:[NSNumber numberWithDouble:42.0]];
[myArray addObject:myModelObject];

//Some time later, you decide to change the number.
[[myArray objectAtIndex:idx] setNumber:[NSNumber numberWithDouble:43.0]];
//Or:
for (MyModelObject *obj in myArray) {
    [obj setNumber:1000.0];
}

*I mean Cocoa objects. The C language does call any pointer, int, etc. an “object”, but this is a different definition.