【问题标题】:Dynamic binding seems like a lie动态绑定似乎是个谎言
【发布时间】:2009-11-08 17:01:11
【问题描述】:

Objective-C 使用动态绑定:即方法调用在运行时解决。

很好。

还有use of dot notation really boils down to a method call

但是,为什么我不能这样做:

#import int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // 拦截异常 @尝试 { @throw [ NSException exceptionWithName:@"名为 ME 的异常!" 原因:@“因为我想” 用户信息:无]; } @catch( id exc ) // 指向异常对象的指针? { //NSLog(@"%@ : %@\n", exc.name, exc.reason ) ; // 非法:请求成员 // 'name' 不是结构体或联合体。. // 如果objective-c 使用动态绑定,和点符号 // 归结为调用 getter,然后 // 为什么我必须在这里转换为具体类型? // 仅当我转换为具体类型 NSException* 时才有效 NSException* nexc = (NSException*)exc ; NSLog(@"%@: %@\n", nexc.name, nexc.reason) ; } [池排水]; 返回0; }

当我听到“动态绑定”时,我在想“所以它应该表现得像一种脚本语言”, 我很惊讶 Objective-C 与 JavaScript 这样的脚本语言相比显得多么不灵活.

【问题讨论】:

  • 您将动态绑定与蛋糕混淆了。 蛋糕是个谎言。
  • “方法调用在运行时解决” 应该真正被认为是“消息调度发生在运行时”。整个 点运算符 的使用更像是一种 hack。
  • 没有什么骇人听闻的;它是方法调用的一个非常明确的同义词,具有一个额外的约束,即类型必须是众所周知的。 (无论人们是否喜欢这个点或认为它是一个很好的补充完全是意见 - 没有评论:)。
  • 说点运算符不是hackish,因为它“定义非常明确”就像说三元组不是hackish,因为“它们在标准中得到了很好的定义”。你可以做[(id)exc name],但你不能做(id)exc.name 的原因是它是一个黑客的原因之一,也是一个糟糕的、考虑不周的黑客。提供不止一种方法来做同样的事情通常是个坏主意,而且这两种方法不对称的事实会导致很多问题和混乱。

标签: objective-c dynamic-binding


【解决方案1】:

您混淆了运行时和编译器。运行时处理这个问题没有问题。问题是点表示法(它是语法糖)需要类型信息,以便编译器消除 Objective-C 对象和 C 结构之间的歧义。

如果你不使用点符号,它可以工作:

NSLog( @"%@ : %@\n", [exc name], [exc reason]) ;

如果类型不是 id,上面会生成一个警告,因为编译器知道它确实知道类型并且不能保证调度会起作用,但它会编译并运行。

从根本上说,当前的问题是编译器需要知道是生成结构加载还是 Objective C 调度,换句话说,使用点表示法,它需要有足够的信息来确定对象和标量之间的区别输入。

【讨论】:

    【解决方案2】:

    动态绑定动态类型不是同义词。 C 是一种强类型语言,特别是参数或返回值的类型至关重要,并且会显着影响代码生成。

    属性专门用于消除歧义。作为其中的一部分,我们决定允许对id使用点语法。

    具体来说,它解决了这种情况:

    @interface Foo
    - (short) length;
    @end
    
    @interface Bar
    - (unsigned long long) length;
    @end
    

    鉴于以上两个单独的头文件,[anObject length] 的编译将给出警告只有两个头文件已被导入。如果只导入了一个头文件,那么调用站点将被编译并返回在头文件中看到的类型。如果调用站点是 other 方法,则会返回一个非常意外的结果。

    对点语法的限制消除了这种潜在的歧义。这也是您通常看到方法的协变声明的原因。 C ABI 只是不干净地支持它(话虽如此,Objective-C 在支持对象类型协变方面做得很差)。

    实际上,Objective-C 开发人员很少使用id 类型。特定的类型声明使编译器能够显着改进其代码验证。

    【讨论】:

    • 像往常一样出色的答案,比尔!了解设计决策的细节总是很高兴。我同意,我很少使用id,因为我经常更喜欢静态类型的好处。
    【解决方案3】:

    Objective-C 确实支持动态绑定。但是,您不能在“id”类型的对象上使用属性 - 但您可以向它发送您想要的任何消息。 (这可能是当前定义/实现中的一个错误……但我们暂时搁置它。)

    如果你这样做了

    NSLog(@"%@ : %@", [exc name], [exc reason] ); 
    

    然后它会工作。请注意,您不需要在 NSLog 语句上添加换行符,因为它们都在不同的行上。

    【讨论】:

    • 确保您阅读了 bbum 的回答。实施不是错误,而是故意的。
    • 很公平,肯定在同一时间回答了:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-11
    • 1970-01-01
    • 2015-08-26
    • 1970-01-01
    相关资源
    最近更新 更多