Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I add nil objects to NSMutableArrays?

I have a situation where I'd like to be able to maintain an array of pointers that might all possibly point to nil.

Equipment *equipment[19];

However, I've found that I cannot set an array of pointers, or a double-pointer, as a property of an object.

My workaround when I can't use C-style arrays is to use the NSArray objects. So I attempted to do something like the following:

NSMutableArray *equipment = [NSMutableArray arrayWithCapacity: NUM_EQUIPSLOTS];
for (int i=0; i<NUM_EQUIPSLOTS; i++) {
    [equipment setObject: nil atIndexedSubscript: i];
}

The idea here being I have an array of empty pointers that will later point to stuff.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(0x246e012 0x1e4be7e 0x2421b6a 0x2421a20 0xebd02 0xde82b 0xc9d5a 0xcb6bd 0x4d525 0xc94fa 0xc8b6a 0xa18157 0xa18747 0xa1994b 0xa2acb5 0xa2bbeb 0xa1d698 0x3176df9 0x3176ad0 0x23e3bf5 0x23e3962 0x2414bb6 0x2413f44 0x2413e1b 0xa1917a 0xa1affc 0xc8526 0x1fa5)
libc++abi.dylib: terminate called throwing an exception

I know I can do this very easily using C-style arrays, and with individual objects. I'd rather do it this way than something dumb like:

Equipment *equipment0 = nil;
Equipment *equipment1 = nil;
Equipment *equipment2 = nil;
// ...
Equipment *equipment18 = nil;

This probably has to do with the structure of the NSArray model itself. Would someone explain to me why this is, and why I can't simply add or set nil objects in NSArray? Thank you in advance.

like image 601
Mike Bell Avatar asked Mar 28 '13 00:03

Mike Bell


People also ask

Can Nsarray contain nil?

arrays can't contain nil.

What is nil in C?

Objective-C builds on C's representation of nothing by adding nil . nil is an object pointer to nothing. Although semantically distinct from NULL , they are technically equivalent.


2 Answers

The "why" is both trivial and unsatisfying. It is because NSMutableArray holds objects, and nil is not an object. ObjC has a strong distinction between objects and primitive types. nil is a primitive type. As CodaFi notes, you can use NSNull or NSPointerArray to address these. The typical solution is NSNull.

like image 197
Rob Napier Avatar answered Sep 28 '22 16:09

Rob Napier


There is no good reason. NSArray and NSMutableArray stores pointers to objects. nil is a decent pointer to an object. The Java equivalent is ArrayList, which does permit null elements. It was just a design choice.

One possible historical reason for this design choice is that the most common way to create an array and fill it with elements is to use the -initWithObjects:... or +arrayWithObjects:... methods, which use varargs to take as many arguments as the user wants to give and put it in the array. Since with varargs in C, it is impossible to determine the number of arguments, the way they chose to indicate how many was to use nil as a "terminator" to signal the end of the list. (There are other ways to indicate the number, e.g. pass the number as the first argument.) The disadvantage of this method was that you cannot put nil as one of the "arguments" that you wanted to put in the array, since it would terminate the list.

However, those methods were not the only ways to create an array and fill it with elements. You could create an empty array and add each one separately, or you could use the -initWithObjects:count: or +arrayWithObjects:count: methods, which are not varargs and thus did not have the nil terminator issue. Now, there is also the array literal syntax (which calls -initWithObjects:count: internally) which makes it even easier. It is perfectly conceivable to have NSArray and NSMutableArray that allows nil elements; just that you cannot use -initWithObjects:... or +arrayWithObjects:... to add the nil elements. However, they chose not to do this.

like image 27
newacct Avatar answered Sep 28 '22 16:09

newacct