views:

1536

answers:

3

I want to create an NSArray with objects of the same value (say NSNumber all initialized to 1) but the count is based on another variable. There doesn't seem to be a way to do this with any of the intializers for NSArray except for one that deals with C-style array.

Any idea if there is a short way to do this?

This is what I am looking for:

NSArray *array = [[NSArray alloc] initWithObject:[NSNumber numberWithInt:0]
                                           count:anIntVariable];

NSNumber is just one example here, it could essentially be any NSObject.

+2  A: 

I can't see any reason why this structure in a non-mutable format would be useful, but I am certain that you have your reasons.

I don't think that you have any choice but to use a NSMutableArray, build it with a for loop, and if it's really important that the result not be mutable, construct a NSArray and use arrayWithArray:

mmc
To get an immutable copy, just use -copy, which returns an array with retain count 1 (and not autoreleased).
Quinn Taylor
Actually, -copy returns an immutable array which you own and must release/autorelease - the retain count could be anything depending on how many other identical arrays there might be. Its best never to talk about retain counts.
Peter N Lewis
An excellent distinction — I stand corrected. Generally a copy returns a newly-initialized object which you alone own, but semantics in a specific situation may dictate otherwise. While the retain count is usually 1, it *could* be higher, and someone else *could* have autoreleased it. Thus, you're correct that it's best to only be concerned with balancing one's own calls to retain/release/autorelease.
Quinn Taylor
A: 

I agree with @mmc, make sure you have a valid reason to have such a structure (instead of just using the same object N times), but I'll assume you do.

There is another way to construct an immutable array which would be slightly faster, but it requires creating a C array of objects and passing it to NSArray's +arrayWithObject:count: method (which returns an autoreleased array, mind you) as follows:

id anObject = [NSNumber numberWithInt:0];
id* buffer = (id*) malloc(sizeof(id) * anIntVariable);
for (int i = 0; i < anIntVariable; i++)
  buffer[i] = anObject;
NSArray* array = [NSArray arrayWithObjects:buffer count:anIntVariable];
free(buffer);

You could accomplish the same thing with even trickier pointer math, but the gains are fairly trivial. Comment if you're interested anyway.

Quinn Taylor
My knowledge is a bit incomplete, so correct me if I'm wrong, but wouldn't this cause all elements of *array to be the same NSNumber object, and not different objects initialized with the same value? I guess it shouldn't matter anyway since NSNumber is immutable, but hey it's what Boon asked for.
alanlcode
@alanlcode: This is likely irrelevent since [NSNumber numberWithInt:0] almost certainly returns a singleton anyway. There is no way to guarentee unique pointers for NSNumber*, so any way you do it you'd have to deal with that issue - and if it is an issue then you'd really have to build your own class with semantics that allowed for two objects to be different and yet represent the same number.
Peter N Lewis
Very true. Also, instances of NSValue (and NSNumber which subclasses it) are immutable, so it's pretty pointless to have N objects of the same value — having the same object at each index is functionally the same and uses less memory. If you're really curious, try doing a -copy and -autorelease each time you insert the object, and see if the instances are different. I've never had reason to do something like this myself.
Quinn Taylor
+1  A: 

Probably the reason there is no such method on NSArray is that the semantics are not well defined. For your case, with an immutable NSNumber, then all the different semantics are equivalent, but imagine if the object you were adding was a mutable object, like NSMutableString for example.

There are three different semantics:

  • retain — You'd end up with ten pointers to the same mutable string, and changing any one would change all ten.

  • copy — You'd end up with ten pointers to the same immutable string, or possibly ten different pointers to immeduable strings with the same value, but either way you'd not be able to change any of them.

  • mutableCopy — You'd end up with ten different mutable string objects, any of which you could change independently.

So Apple could write three variants of the method, or have some sort of parameter to control the semantics, both of which are ugly, so instead they left it to you to write the code. If you want, you can add it as an NSArray category method, just be sure you understand the semantic options and make it clear.

The method:

-(id)initWithArray:(NSArray *)array copyItems:(BOOL)flag

has this same issue.

Quinn's solution using arrayWithObjects:count: is a reasonably good one, probably about the best you can get for the general case. Put it in an NSArray category and that's about as good as it is going to get.

Peter N Lewis