【问题标题】:What is preferable in objective-c: id or explicit type?在objective-c中更可取的是:id还是显式类型?
【发布时间】:2012-03-30 12:32:39
【问题描述】:

什么更好,为什么?

在类初始化方法和代码中的常用变量等情况下,什么更好?

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    什么更好,为什么?

    明确的输入信息总是更好,除非你因为某种原因不能使用它(见下文)。

    它允许编译器更严格地验证代码,并在编译时捕获许多错误,否则会导致您的应用在运行时崩溃。

    很久很久以前,API 中的所有内容都使用id。事实证明,这完全是一种痛苦。脆弱并导致许多本来可以使用特定类型捕获的崩溃。

    所以,它被改变了。 (这是 1994 年左右)。

    在这样的情况下什么更好 类初始化方法和通常 代码中的变量?

    对于init,您别无选择,只能使用通用的(id) 返回类型。 Objective-C 不支持协变或反变声明,也没有一种机制可以泛化init 的声明,同时还支持特定类型检查。

    同样适用于retainobjectAtIndex:addObject: 和许多其他采用或返回多种对象之一(或将它们作为参数)的方法。

    而且,不,idNSView* 之间绝对没有任何性能差异。

    你能举个例子吗? 请问打字会出问题吗?

    如果你写了:

    - (MyClass *) init;
    

    在子类中:

    - (MySubclass *) init;
    

    您很可能会从 wazoo 中获得编译器警告,或者您必须将 wazoo 类型转换出来。

    【讨论】:

      【解决方案2】:

      在最新版本的 clang(在 Lion 中)您实际上不应返回 id,而应返回 instancetype。这是在返回类型中使用的关键字,用于指定它返回的类型是接收消息的类的实例。它现在是 OS X Lion 上 init 方法的首选返回类型。

      【讨论】:

        【解决方案3】:

        显式类型提供构建时保护,如果您执行诸如强制转换或对某些可能不起作用的操作执行操作等操作,它会通知您可能出现的问题。

        显式输入还有助于防止错误输入对象的非明显传输,这是通过您的代码中您没有考虑过的路径传播的东西,结果是意外类型。这种错误通常在程序经过大量测试后才会变得清晰,在发布后更常见。

        它也对未来的程序员有帮助(包括你未来的自己)尝试使用你的代码,使他们更有可能一眼就知道一个对象应该是什么.结果,它使代码更加“自我记录”。

        有些东西不能有有意义的类型,因为没有类型实际适用。其他时候您需要使用id,因为您需要能够接受任何类型的对象。例如,Cocoa Touch 在引用消息的sender 时使用它,因为任何东西都可以发送它;指定显式类型根本行不通。

        不过,绝大多数情况下,显式类型对您有利。

        【讨论】:

        • 你能举个例子,当显式输入会导致问题吗?
        • @Andrew 我修改了我的答案,不要留下那个模糊的“问题”词,举例说明你什么时候不能。感谢您指出。另请参阅 bbum 的答案以获取一个很好的示例。
        【解决方案4】:

        尽可能使用具体的类型,但不能更具体。考虑您如何使用任何特定的变量、参数或返回类型并适当地设置其类型。

        例如,UITableView 的dataSource 属性被声明为id<UITableViewDataSource>,因为表视图只关心其数据源是符合UITableViewDataSource 协议的某个对象。这使得数据源足够灵活,可以与实现协议的任何特定类一起使用,但如果您尝试将未实现该协议的对象分配为数据源,编译器仍会发出警告。

        如果你太具体,那么你的代码就会变得不灵活,只接受不是严格必要的特定实现(即,当你真的可以使用任何 NSString 时要求 NSMutableString)。

        如果您太模糊(例如,将所有内容都输入为id),那么您将无法识别何时将无法识别的选择器发送到特定实例,并且编译器无法识别任何数量的无效语句。

        对于init 方法,请遵循The Objective-C Programming Language 中的建议

        初始化方法的返回类型应该是id。

        这样做的原因是 id 表明该类是故意不考虑的——该类是未指定的并且可能会根据调用的上下文进行更改。例如,NSString 提供了一个方法 initWithFormat:。然而,当发送到 NSMutableString 的实例(NSString 的子类)时,消息返回 NSMutableString 的实例,而不是 NSString。 (不过,另请参见“组合分配和初始化”中给出的单例示例。)

        【讨论】:

          【解决方案5】:

          我认为两者之间没有性能差异。 你可以让 id 为 init 返回类型,因为你可以转换你的 init 的结果。

          例如:

          Toto *foo = [[Toto alloc] init];
          id foo2 = [[Toto alloc] init]; 
          

          两者都有效,但您必须像 (Toto *)foo 那样转换 foo2 变量,以便在不创建编译器警告的情况下访问实例的属性或方法。即使它工作正常......

          我认为一些开发人员允许使用 id 是因为他们只是通过实例传递变量而不使用它。这种使用允许不导入 .h

          问候,
          KL94

          【讨论】:

          • 没有性能差异;甚至生成的代码也没有区别。
          • 是的。修复了语法和我误导的否决票。对此感到抱歉。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-14
          • 1970-01-01
          • 2015-09-11
          • 1970-01-01
          相关资源
          最近更新 更多