0

I want to create a NSMutableArray to represent a game board that holds grid element (assume I have a chess class). In this case, I already know the size of the board so I want to create an array by initWithCapacity:[size] and then initialize them as nil. During the game, I may insert or remove chess object into/from this array based on game. I need to check if some cell is nil sometimes.

Clearly initWithCapacity only allocate memory, but gives an empty array whose element is not assessable. I think insert [NSNull null] one by one is inefficient (I can turn to use 0 to represent nil but still not what I want).

Is there any type/structure in Objective C like a C/C++ array for my purpose? Or is it wise to use C/C++ array here? (e.g. Chess myArray[size])

Xi Zhu
  • 311
  • 4
  • 10
  • 1
    It is unclear what you're asking here. Are you asking how to use nil with arrays, or how to populate an array with them? – Andy Ibanez Jan 27 '15 at 16:14
  • Read the spec!! You cannot put `nil` values in an NS(Mutable)Array. If you need to represent "null", use the NSNull singleton object. – Hot Licks Jan 27 '15 at 16:22
  • @HotLicks, they already know about NSNull, but (mistakenly) worry that it's inefficient. – James Webster Jan 27 '15 at 16:23
  • NSNull is quite efficient. Among other things, you can compare to it directly (`if (somepointer == [NSNull null])`) vs having to use some sort of "equals" method call. – Hot Licks Jan 27 '15 at 16:26
  • Yeah, I include in my answer that NSNull is efficient. It's a singleton, so won't be allocating lots of memory unnecessarily. – James Webster Jan 27 '15 at 16:48
  • @AndyIbanez I'm confused about how to populate an array with `[NSNull null]`. Is there a better way to fill the array with `nil` like C/C++ array when the array is created, instead of enumerating the array (e.g. `for (i=0;i – Xi Zhu Jan 27 '15 at 18:53
  • Offhand, I don't think there's any one-statement way to say "fill the array with 27 copies of this object", or some such. You gotta write the loop. – Hot Licks Jan 27 '15 at 19:59

2 Answers2

2

It is by design that NSMutableArrays and other collections do not permit nil and [NSNull null] is used as a placeholder for the concept of "nothing" instead.

I think insert [NSNull null] one by one is inefficient

[NSNull null] is a singleton, so won't allocate lots of memory unnecessarily and is not inefficient.

This answer has more information.


Anther efficiency I'm concerning about [NSNull null] is when I first create the array, if this array is kind of large (say 100 entries)

100 elements isn't a problem. Your device will be able to iterate 100 elements very quickly. Time it if you like.

is enumeration the only way I can assign a nil to each of these 100 entries? (e.g. for (i=0;i<size;i++) {[myArray addObject:[NSNull null]];}

It's the first way I would think of doing it.


"Premature optimisation is the root of all evil"
Donald Knuth

You seem to be concentrating on optimisation too early. You should favour readability over efficiency at this point.

When your app seems to slow down, or near the end of a release, profile the application and find out what, if any problems exist. Otherwise you may find yourself spending a day "optimising" a for loop to find that you've saved 0.000001s per update.

Moreover, readable code is easier to:

  • debug
  • update
  • maintain
  • share

Micro-optimised code takes longer to produce, is prone to bugs, difficult to debug and maintain and often impossible to share as another developer may not know how to interpret your optimisations.

That's not to say "don't optimise", rather concentrate on optimising the biggest problems.

Community
  • 1
  • 1
James Webster
  • 31,873
  • 11
  • 70
  • 114
  • @gnasher729 Yes after the first `nil` nothing after that will be read. See http://stackoverflow.com/questions/12908045/nsarray-arraywithobjects-if-nil-is-meant-to-mark-array-end-can-i-do-nil-ni – Nate Lee Jan 27 '15 at 16:20
  • Read the answer to the question you've linked, @NateLee (and James Webster): `nil` is not a member of the collection -- it's only used as a sentinel for the end of the _variadic arguments_ to the _method_. The array does not need a sentinel value; it knows its own length (and [isn't stored contiguously anyways](http://ridiculousfish.com/blog/posts/array.html)). – jscs Jan 27 '15 at 17:45
  • Comment removed because the offending text was fixed. – gnasher729 Jan 27 '15 at 17:57
  • Thanks for answering. Anther efficiency I'm concerning about `[NSNull null]` is when I first create the array, if this array is kind of large (say 100 entries), is enumeration the only way I can assign a `nil` to each of these 100 entries? (e.g. `for (i=0;i – Xi Zhu Jan 27 '15 at 18:50
  • @XiZhu, I've edited my answer to respond to the questions in the comment. – James Webster Jan 27 '15 at 19:04
  • Yeah, we need to cut off premature optimization at it's routes. ;) – Hot Licks Jan 27 '15 at 20:00
0

You can use something like this:

NSMutableArray *array = [NSMutableArray arrayWithArray:@[@"First", @"Second", @"Third"]];
[array addObject:[NSNull null]];

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if (![obj isKindOfClass:[NSNull class]]) {
        // Do something
    }
}];
Igor Leonovich
  • 458
  • 4
  • 13