Reputation: 1279
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
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
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
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