动态绑定似乎是一个谎言

时间:2009-11-08 17:01:11

标签: objective-c dynamic-binding

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

精细。

use of dot notation really boils down to a method call

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

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


  // Intercept the exception
  @try
  {
    @throw [ NSException 
            exceptionWithName:@"Exception named ME!" 
            reason:@"Because i wanted to" 
            userInfo:nil ] ;
  }
  @catch( id exc ) // pointer to an exception object?
  {



    //NSLog( @"%@ : %@\n", exc.name, exc.reason ) ; // ILLEGAL:  Request for member 
    // 'name' in something not a structure or union..
    // If objective-c uses dynamic binding, and dot notation
    // boils down to calling the getter, then
    // WHY do I have to cast to the concrete type here?

    // Only works if I cast to the concrete type NSException*
    NSException* nexc = (NSException*)exc ;
    NSLog( @"%@ : %@\n", nexc.name, nexc.reason ) ;



  }



  [pool drain];
    return 0;
}

当我听到“动态绑定”时,我在想“所以它应该像脚本语言一样”,我很惊讶Objective-C似乎与JavaScript之类的脚本语言相比

3 个答案:

答案 0 :(得分:17)

您对运行时和编译器感到困惑。运行时没有问题可以解决这个问题。问题是点符号(这是语法糖)需要编译器的类型信息来消除Objective-C对象和C结构之间的歧义。

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

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

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

基本上,手头的问题是编译器需要知道是否生成结构加载或Objective C调度,换句话说,使用点符号需要有足够的信息来确定对象和标量之间的差异类型。

答案 1 :(得分:17)

动态绑定动态类型不是同义词。 C是一种强类型语言,特别是参数或返回值的类型很重要,可能会严重影响代码生成。

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

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

@interface Foo
- (short) length;
@end

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

鉴于以上两个单独的头文件,[anObject length]的编译将仅警告两个头文件已被导入。如果仅导入了一个头文件,则将编译调用站点,返回标头中看到的类型。如果调用站点用于其他方法,则会返回非常意外的结果。

点语法的限制消除了这种潜在的歧义。这也是通常会看到方法的共变量声明的原因。 C ABI只是不干净地支持它(据说,Objective-C在支持对象类型协方差方面表现不佳)。

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

答案 2 :(得分:0)

Objective-C确实支持动态绑定。但是,您不能在“id”类型的对象上使用属性 - 但您可以向其发送任何所需的消息。 (这可能是当前定义/实现中的一个错误......但是现在让我们把它放在一边。)

如果你做了

NSLog(@"%@ : %@", [exc name], [exc reason] ); 
那么它会起作用。请注意,您不需要在NSLog语句上添加换行符,因为它们都在不同的行中。