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之类的脚本语言相比
答案 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语句上添加换行符,因为它们都在不同的行中。