【问题标题】:Why can't I add nil objects to NSMutableArrays?为什么我不能将 nil 对象添加到 NSMutableArrays?
【发布时间】:2013-03-28 00:51:03
【问题描述】:

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

Equipment *equipment[19];

但是,我发现我无法将指针数组或双指针设置为对象的属性。

当我不能使用 C 样式数组时,我的解决方法是使用 NSArray 对象。因此,我尝试执行以下操作:

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

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

*** 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

我知道我可以使用 C 风格的数组和单个对象轻松地做到这一点。我宁愿这样做而不是像这样愚蠢的事情:

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

这可能与 NSArray 模型本身的结构有关。有人会向我解释为什么会这样,以及为什么我不能简单地在 NSArray 中添加或设置 nil 对象吗?提前谢谢你。

【问题讨论】:

  • 使用 NSNull 模拟 nil,或者使用 NSPointerArray 模拟集合中的实际 NULL。
  • 如果您正在为 iOS6+ 或 OS X 10.5+ 编写代码,那么可以考虑使用 NSPointerArray。 developer.apple.com/library/mac/#documentation/Cocoa/Reference/…
  • 如果你想知道为什么,反编译Core Foundation,看看CFArray在向自身添加对象时做了什么。如果你能通过足够多的内联 asm 和晦涩难懂的 CF 函数,你就会明白为什么。
  • @CodaFi 实际上,我完全可以这样做!最后,我已经解决了我遇到的问题,但是为了真正回答我的问题,我必须完全按照你的建议去做。谢谢指导! :)
  • 没有理由反编译 Core Foundation。其中大部分是开源的。 opensource.apple.com/source/CF/CF-744.12/CFArray.c

标签: objective-c c nsmutablearray nsarray null


【解决方案1】:

“为什么”既琐碎又令人不满意。这是因为NSMutableArray 持有对象,而nil 不是对象。 ObjC 在对象和原始类型之间有很大的区别。 nil 是原始类型。正如CodaFi 所说,您可以使用NSNullNSPointerArray 来解决这些问题。典型的解决方案是NSNull

【讨论】:

  • 我什至知道有些人将空的 NSMutableArrays 分配到 nil 对象应该在的位置。他不需要 NSNull,只需要一些分隔类型。
  • “深”“为什么”是ObjC是SmallTalk概念,分层在C之上。很多东西不是对象,因为在底层C中实现效率低或不方便。这就是本质像 ObjC 这样的混合语言。对于 Cocoa 的所有美妙之处,ObjC 仍然只是基本基于 C 语言之上的一个薄对象贴面。
  • "这是因为 NSMutableArray 包含对象" 不正确。 NSMutableArray 持有指向对象的指针。在 Objective-C 中对“对象”的所有操作都必须通过指向对象的指针。 “对象”本身不是值。
  • @newacct,这是一个很好的评论,但它可能更令人困惑。当您说“它包含指向对象的指针”时,这表明 NULL 指针应该是可以接受的(因为它适用于指向对象的指针的 C++ 向量)。但在 ObjC 中,这不是真的。数组不能保存指向对象的任意指针;它们只能保存实际实例化的对象引用(在 ObjC 中通常称为“对象”)。但我同意一些学生,你的说法更清楚。最终,所有学生都应该理解其中的区别,只是很难知道何时引入哪个概念。
  • @RobNapier:当你说“数组不能保存指向对象的任意指针”时,你的意思是NSArray?制作一个允许nil 的数组类将是微不足道的(而且更一致)。至于任意非nil 指针,唯一的障碍是您不能向它们发送retainrelease 消息。但是,您可以retainrelease 消息发送到nil,因此对于所有关心的数组,它的行为与指向活动对象的指针没有什么不同。没有特别的理由制定额外的规则来禁止nil
【解决方案2】:

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

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

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

【讨论】:

  • 当我阅读这里的第一段时,我看到了我所讨论的完全混乱 :D(这没有错;它只会让那些来自其他语言的人更加困惑。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多