【问题标题】:Why does NSArray arrayWithObjects and friends return id and not NSArray*?为什么 NSArray arrayWithObjects 和朋友返回 id 而不是 NSArray*?
【发布时间】:2013-03-06 09:30:44
【问题描述】:

这里是基本的 Cocoa 新手问题……这似乎是 Cocoa 中非常常见的模式。为什么像[NSArray arrayWithObjects: ...]这样的初始化方法和自动释放对象创建方法返回id?为什么返回 NSArray *(或正在创建的实际类型)并不是更好?

【问题讨论】:

    标签: objective-c cocoa


    【解决方案1】:

    init 方法返回 id,因此它们可以返回与其超类相同的类。

    Objective-C 集合类返回 id,因为它们可以存储任何类型的 Objective-C 对象。

    【讨论】:

    • 查看我对贾斯汀关于协变返回类型的回答的评论
    • @Jean-PhilippePellet 否 Objective-C 不支持协变返回类型。看到这个问题:stackoverflow.com/questions/2433504/…
    • 好的,所以我的后续问题是:为什么不应该返回instancetype 而不是id
    • @Jean-PhilippePellet instancetype 是 clang (clang.llvm.org/docs/LanguageExtensions.html#objc_instancetype) 引入的扩展,并且库在 clang 之前就已经存在,所以我猜 id 主要用于历史目的。
    • @Jean-PhilippePellet 同意;在这样的构造方法中返回实际类型是可以的。
    【解决方案2】:

    另一个原因是返回值的类型选择器匹配。如果[NSArray arrayWithObjects: ...] 返回一个NSArray(通过声明),那么NSMutableArray 需要用不同的返回类型重新声明arrayWithObjects:(否则在编写NSMutableArray * a = [NSMutableArray arrayWithArray:] 时会收到警告)。

    即使你走这条路,当编译器尝试将选择器与类型/非类型匹配时,消息链也会很快导致歧义。所以......选择器的返回和参数类型在这种情况下应该匹配。因此,使用了返回类型id

    如果您尝试使用此类构造函数构建严格类型的 objc 层次结构并使用高警告级别,您将看到这种歧义是如何展开的。当然,NSArray/NSMutableArray 的例子足以说明问题。

    【讨论】:

    • Java 和 C++ 允许被覆盖的方法具有协变返回类型。那么Objective没有这种东西呢?
    • @Jean-PhilippePellet 使用这种书面风格不是一个好主意,尤其是在处理非 objc 对象时。您需要的所有动态都存在,但编译器很难匹配类型/选择器/返回类型。一个 objc 选择器没有定义返回类型或参数类型(尽管它们可以查询特定的实现),并且调度总是动态的。因为调度是动态的,你也应该支持选择器的参数和返回类型来匹配。它在实践中运行良好。 [NSMutableArray array] 显然返回 NSMutableArray
    • @Jean-PhilippePellet(续)尽管(源级别)类型擦除虽然id。和 trojanfoe 链接了 bbum 的一个很好的解释。当然,您可以随意尝试,但初始化程序和构造函数通常是单行的,因此您可以立即(重新)使用变量声明来引入类型。
    • 但是我可以重新引入错误的类型,而编译器甚至不会发出警告。我可以完美无误地写NSMutableArray *a1 = [NSArray array]; [a1 addObject:@"wrong!"];,这不是很令人不安吗?
    【解决方案3】:

    实际上它确实返回一个 NSArray/NSMutalbeArray/whatever。

    只是id是init的通用返回值。所以返回值被声明为 id 但它是一个正在返回的 NSArray。

    但坦率地说,对于你的“为什么”问题,我无法给你任何好的答案。每当我覆盖子类中的 init 方法时,如果类的名称是 ABC,我会让它们返回 ABC*。它工作正常。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多