tiritea
tiritea

Reputation: 1279

NSArrayWithObject:nil asserts, but NSArrayWithObjects:nil doesn't. Bug or feature?

Whilst debugging a problem with UICollectionView -reloadItemsAtIndexPaths, I traced an assert to a condition where I (normally) need to pass this method a single element array (I have only one cell to reload). Hence, somewhat obviously, I used the equivalent of the following to generate the necessary array:

NSIndexPath *foo = ...
NSArray *bar = [NSArray arrayWithObject:foo];
[mycollectionview reloadItemsAtIndexPaths:bar];

However, in the special case when mycollectionview is still empty then the indexpath foo is nil (ie no cell to reload), it appears arrayWithObject: asserts with the error:

2014-10-11 12:45:08.066 Xulu[26594:90b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'

HOWEVER, if I instead use

NSArray *bar = [NSArray arrayWithObjects:foo,nil];

Everything is fine.

So my question is, is the fact that [NSArray arrayWithObject:nil] asserts a bug, or an undocumented feature? The Apple docs saying nothing about the parameter having to be non-nil. I see lots of posts about using nil with arrayWithObjects, but nothing about arrayWithObject and nil. And this seems like a not-that-unusual situation...

Upvotes: 2

Views: 218

Answers (3)

tiritea
tiritea

Reputation: 1279

To followup on my own question, after further digging - and in lieu of the comments above - this is probably working-as-designed; ie an arguably ill-documented 'feature', not a bug... In particular, Apple's documentation for insertObjectAtIndex: does clearly state:

(void)insertObject:(id)anObject atIndex:(NSUInteger)index

Parameters

anObject

The object to add to the array's content. This value must not be nil.

Important: Raises an NSInvalidArgumentException if anObject is nil.

Probably the arrayWithObject: documentation could benefit with something similar. Thnx for those that took the time to respond. This can be closed.

Upvotes: 0

rickster
rickster

Reputation: 126157

By definition, arrayWithObject's parameter must be a pointer which is legal as an element of an NSArray. An NSArray cannot contain nil, so it's a design error to pass nil to this method — hence the exception.

On the other hand, arrayWithObjects takes a nil-terminated list of arguments. Passing nil alone constitutes passing an empty list, creating an empty array. Nothing wrong with that.

However, in modern ObjC it's best to use neither method. Instead, use array literals:

NSArray *bar = @[foo];

This makes your intent clearer to future readers of your code, catches problematic use of nil with a clearer error message, and avoids the kind of silent failures that can arise from use of arrayWithObjects and unintended nils.

Upvotes: 2

Paulw11
Paulw11

Reputation: 114975

You can't put nil into an array - You have to store an NSNull object

NSArray *bar = [NSArray arrayWithObjects:foo,nil];

creates a one element array containing foo - nil is the sentinel indicating the end of the list of objects to put into the array - it isn't put into the array

Now, if foo itself is nil then this is the same as saying

NSArray *bar = [NSArray arrayWithObjects:nil,nil];  

The first nil terminates the list and the second nil is ignored - so you end up with an empty array

NSArray *bar = [NSArray arrayWithObject:foo];

Creates a one element array and puts the specified object into it - but your object is nil and you can't store nil so you get the assertion failure.

Upvotes: 1

Related Questions