为什么我不能将nil对象添加到NSMutableArrays?

Mik*_*ell 6 c null objective-c nsmutablearray nsarray

我有一种情况,我希望能够维护一个可能都指向nil的指针数组.

Equipment *equipment[19];
Run Code Online (Sandbox Code Playgroud)

但是,我发现我不能将指针数组或双指针设置为对象的属性.

当我不能使用C风格的数组时,我的解决方法是使用NSArray对象.所以我尝试做类似以下的事情:

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

这里的想法是我有一个空指针数组,稍后会指向东西.

*** 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
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用C风格的数组和单个对象轻松地完成这项工作.我宁愿这样做而不是像哑巴一样:

Equipment *equipment0 = nil;
Equipment *equipment1 = nil;
Equipment *equipment2 = nil;
// ...
Equipment *equipment18 = nil;
Run Code Online (Sandbox Code Playgroud)

这可能与NSArray模型本身的结构有关.有人会向我解释为什么会这样,为什么我不能简单地在NSArray中添加或设置nil对象?先感谢您.

Rob*_*ier 9

"为什么"既微不足道也不令人满意.这是因为NSMutableArray保持对象,而nil不是对象.ObjC在对象和原始类型之间有很强的区别.nil是一种原始类型.作为CodaFi注释,您可以使用NSNullNSPointerArray解决这些问题.典型的解决方案是NSNull.

  • "这是因为NSMutableArray持有对象"不正确.`NSMutableArray`拥有*指向对象*的指针.在Objective-C中使用"对象"进行的所有操作都必须通过指向对象的指针."物体"本身不是价值. (3认同)
  • @newacct,这是一个很好的评论,但它可能更令人困惑.当你说"它保存指向对象的指针"时,这表明"NULL"指针应该是可接受的(就像指向对象的C++向量一样).但在ObjC中,这不是真的; 数组不能保存任意指向对象的指针; 它们只能保存实际的实例化对象引用(在ObjC中通常称为"对象").但我同意一些学生,你说的方式更清楚.最终所有学生都应该理解这种区别,知道什么时候引入哪个概念才具有挑战性. (3认同)
  • @RobNapier:当你说"数组不能保存对象的任意指针"时,你的意思是"NSArray"吗?创建一个允许"nil"的数组类将是微不足道的(并且更加一致).对于任意非"nil"指针,唯一的障碍是你不能向它们发送`retain`和`release`消息.但是,您可以*将`retain`和`release`消息发送到`nil`,因此对于所有数组关注,它与指向活动对象的指针没有什么不同.没有特别的理由要做出一个额外的规则来禁止"nil". (2认同)

new*_*cct 5

没有充分的理由。NSArrayNSMutableArray存储指向对象的指针。nil是一个像样的指向对象的指针。Java 等价物是ArrayList,它允许null元素。这只是一个设计选择。

这种设计选择的一个可能的历史原因是创建数组并用元素填充它的最常见方法是使用-initWithObjects:...or+arrayWithObjects:...方法,该方法使用可变参数来获取用户想要提供的尽可能多的参数并将其放入数组中. 由于在 C 中使用 varargs,无法确定参数的数量,他们选择指示多少的方式nil用作“终止符”以表示列表的结尾。(还有其他方法可以表示数字,例如将数字作为第一个参数传递。)此方法的缺点是您不能将其nil作为要放入数组的“参数”之一放入,因为它会终止列表。

然而,这些方法并不是创建数组并用元素填充它的唯一方法。您可以创建一个空数组并分别添加每个数组,或者您可以使用-initWithObjects:count:or+arrayWithObjects:count:方法,它们不是可变参数,因此没有nil终止符问题。现在,还有数组文字语法(在-initWithObjects:count:内部调用),这使它变得更加容易。完全可以想象拥有NSArrayNSMutableArray允许nil元素;只是您不能使用-initWithObjects:...+arrayWithObjects:...添加nil元素。然而,他们选择不这样做。