NSMutableArray add Object as pointer only?
Asked Answered
S

4

5

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.

Spec answered 30/3, 2009 at 8:33 Comment(0)
O
16

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.

Overly answered 30/3, 2009 at 10:58 Comment(0)
D
10

Your problem is that NSNumber objects are immutable; meaning that you cannot change their value. So in order to change a value you have to create a new NSNumber object. E.g:

myNumber = [NSNumber numberWithDouble:[myNumber doubleValue]+1.0]

Now, of course you have myNumber point to different object than the one you added to the array. So you have to update the array by replacing the changed NSNumber object:

[myArray replaceObjectAtIndex:0 withObject:myNumber]

Well, this leaves you with the problem that you have to store the index together with each NSNumber in order to be able to update the array. Which is incovenient if you want to pass the NSNumber object around and allow changing the value.

You could solve this problem by introducing a wrapper object that you wrap around NSNumber in order to allow transparent updates or you just could create your own class that handles your doubleValue (somewhat a mutable NSNumber class).

Dissension answered 30/3, 2009 at 9:12 Comment(0)
S
3

If you change the pointer myNumber then, as you said, the value stored in the array does not change. However, the pointer stored in the array is a copy of myNumber, so if you change the object that myNumber points to the object that the array element points to will reflect that change because it's the same object.

What you seem to want to do is to make the array point to a different object (whenever you change myNumber). You'll have to do this manually by using, for example -replaceObjectAtIndex:withObject:, like so:

NSNumber *myNumber = [NSNumber numberWithDouble: 3.141592];
int myNumberIndex = [myArray count];
[myArray addObject: myNumber];

myNumber = ...; //whatever
[myArray replaceObjectAtIndex: myNumberIndex withObject: myNumber];

What this code does, basically, is store the index of the object that you put into myArray and then replace that object with the new one.

Sirocco answered 30/3, 2009 at 9:11 Comment(0)
H
2

It sounds like you want something like NSPointerArray...

NSPointerArray is probably one of the most powerful of (these) specialized collection classes. It specifies an NSArray-like interface, but allows for the insertion of null values (and arbitrary pointers). Additionally, by specifying certain options when creating an instance of NSPointerArray , you can configure your array to have specific memory management policies with regard to the objects stored within it.

You specify the options for your instance of NSPointerArray when you create it using the methods -initWithOptions: or -initWithPointerFunctions:. When using the method -initWithOptions:`, you are specifying that the array that you are creating will obey the policies set forth by the options that you are passing as a parameter. The options,which are specified using a bitwise-or, set specific policies or “personalities” for the array.

and it goes on...

When you pass this instance to the NSPointerArray, it will then use the functions that you have defined when objects are inserted, removed, and so on, in place of the normal retain, release, and other methods that would be used in a normal NSArray.

Source (but I would look elsewhere if you want to know more)

Honeycomb answered 23/9, 2012 at 11:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.