代码之家  ›  专栏  ›  技术社区  ›  pjb3

为什么NSArray arrayWithObjects需要终止nil?

  •  15
  • pjb3  · 技术社区  · 17 年前

    我知道它标志着一组vararg的结束,但是为什么不能以不需要nil的方式实现它呢?

    6 回复  |  直到 17 年前
        1
  •  18
  •   Wayne Hartman    13 年前

    这一切都与C调用ABI有关。

    考虑这些方法:

    - (id)initWithFormat:(NSString *)format, ...;
    + (id)arrayWithObjects:(id)firstObj, ...;
    + (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
    

    这个 ... 告诉编译器可能存在任意类型的可变数量的参数。编译器无法知道需要哪些类型(真正的定义有助于这一点的标记)。

    必须 是一堆对象,后跟一个零。字典需要一组对象对,后跟nil。最后,string方法需要一组与格式字符串中的类型匹配的参数。

    所有这些行为都与所调用的方法直接相关,如果API的作者决定选择“难以使用”,则可以在运行时修改解码变量参数的行为,这只会让生活变得困难。

    一句话:C ABI的语法不允许指定一个方法或函数接受数量可变的参数,并且对参数或其终止具有任何类型的约束集。

    Objective-C可以仅更改方法声明的规则&调用,但这对C函数或C++没有帮助,这两个Objule- C必须保持兼容。

        2
  •  3
  •   olliej    17 年前

    任何varargs函数都需要知道存在多少个参数——如果不使用nil terminate,则只需要其他参数。在本例中,最明显的选择是长度,但是每次更改数组中的项数时都需要更新length参数,这可能会很麻烦,甚至更糟。

        3
  •  2
  •   Rob Napier    17 年前

    @bbum提供了一些很好的技术细节。下面是一些关于“他们为什么不修复它”的实际想法

    记住:C只是汇编程序,Obj-C只是C。。。当然可以重新设计,但几乎没有压力这么做。您仍然无法将nil放入数组中(这需要进行巨大的更改)。编译器现在警告您,如果您忘记了nil,那么开发人员不会对此抱怨太多。这样做的代价是使语言比同类语言简单得多,从几十年的C编译器优化中获益,并保证与C代码的兼容性。

    从@bbum的讨论中,有一点应该变得清楚:NSArray不是Objective-C的语言特性。C-array是一种语言特性,但NSArray只是另一个对象,与您编写的对象没有什么不同。

        4
  •  2
  •   Peter DeWeese    15 年前

    有各种各样的解决方法,但我目前最喜欢的是应用程序,而不是发布的框架。在方法中接受NSArray而不是“…”,然后用下面的便利宏填充它,该宏位于前缀文件或实用程序头中。

    #定义$array(objs…[NSArray arrayWithObjects:objs,nil]

    它将允许多个标记良好的可变长度参数,并且您将从必须使用第一个参数、然后使用va_list及其兄弟的陈旧模式中解放出来,转而使用for-in循环或许多其他可用的收集工具。

    [self-findMatchingSetAndAlert:@“标题”领带:$array(tie1、tie2、tie3)衬衫:$array(shirt1、shirt2、shirt3、shirt4)];

    如果有人知道如何实现非零分隔列表,如stringWithFormat,请告诉我们!它使用属性和宏或专门为格式化而设计的东西,但它们是以某种方式实现的。

        5
  •  1
  •   Stephan    14 年前

    现在可以在Objective-C中使用新的集合文本(别名容器文本)。请参阅 http://clang.llvm.org/docs/ObjectiveCLiterals.html

        6
  •  0
  •   turingtested    7 年前

    原因很简单,在场景背后是一个for循环,它将继续从 va_list nil . 因此,结束条件可以是任何东西,例如字符串“stop”。但是 他其实很聪明。

    假设我们有三个对象 hansel gretel 和 woodcutter 并创建它们的数组:

    NSArray *startCharacters = [NSArray arrayWithObjects:hansel, gretel, woodcutter, nil];
    

    现在,我们意识到 从来没有发起过,所以 startCharacters 仍将使用 汉塞尔 和 格雷特尔 对象,从它到达 樵夫 它终止了。因此,在 arrayWithObjects: 防止应用程序崩溃。

    如果你不想写出来

    NSArray *startCharacters = @[hansel, gretel, woodcutter];
    

    它是有效的,它较短,但如果对象是 . 所以结论是 带对象的阵列: