Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

teek

macrumors member
Original poster
Feb 12, 2008
88
0
Norway
What is the difference between these two ways of creating an NSArray.

Besides one being a class method and the other being an instance method. What is the difference ? When I use the class method my application will crash when I try to access the elements of my array.

+(id)arrayWithObjects:(id)firstObj, ...;

-(id)initWithObjects:(id)firstObj, ...;

myData = [NSArray alloc] initWithObjects:mad:"foo",@"bar",nil];

do something with myData[index] all OK.

myData = [NSArray arrayWithObjects:mad:"foo",@"bar",nil];

do something with myData[index] will crash without any exception or stacktrace.


What am I missing ?
 
+(id)arrayWithObjects: (id)firstObj, ...

This will return an NSArray, which will be valid in the current scope. If you need this later, you need to retain the array (and release it when you're done).

-(id)initWithObjects: (id)firstObj, ...

This returns an NSArray with a retain count of 1. You don't need to retain it, but you do need to release it when done.

They're also used slightly differently, init.. methods are normally used in conjunction with alloc.

Code:
NSArray* myArray = [NSArray arrayWithObjects: ......];
[myArray retain];
.
.
[myArray release];

OR

NSArray* myArray = [[NSArray alloc] initWithObjects: .....];
.
.
[myArray release];

Edit - I should add, the retain/release lines may not be necessary if you're using garbage collection; but I think it's useful to know all the same.
 
Ok I see. But how do I know when I have to retain the object ? I don't get it.
 
If you create an object with a class method such as arrayWith... , it's only guaranteed to be valid for the current scope (i.e. in the function/method you call arrayWith...). If you (say) assign that array to an instance variable, and want to use it later, you need to retain it.

E.g.

Code:
- (void) setupArray
{
    _theArray = [NSArray arrayWithObjects:....];

    // _theArray is valid here
}

- (void) useArray
{
    id first = [_theArray objectAtIndex:0];
    // _theArray may not be valid here, this will probably crash!
}
.
.
[self setupArray];
[self useArray]

If you wanted the above example to work correctly, you'd need to add a [_theArray retain] as the second line in setupArray.

As a general rule:
- if you use alloc..init, or if you use copy.. methods, then you need to release the objects they return once you're finished with them.

- For objects returned from other methods (such as arrayWithObjects:...) you need to retain them if you need to use them in another scope.

- Every object you retain, you need to release later

So, you can use the two methods you mentioned for the same tasks, but generally you'd use arrayWithObjects if you want to create an array just for the current function/method; whereas you'd normally use alloc & initWithObjects: if you're creating a "permanent" array which you'll be using often/later.
 
Ah this is good info, thank you very much whooleytoo!
And thank you too gnasher729, reading it now :)
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.