9.3 编译时和运行时检查

因为存储在id变量中的对象类型在编译时无法确定,所以一些测试推迟到运行时进行,就是说,推迟到程序执行时。

考虑下列代码序列:


Fraction*f1=[[Fraction alloc]init];

[f1 setReal:10.0 andImaginary:2.5];


回顾一下,setReal:andImaginary:方法应用于复数而不是分数,当编译包含这些语句的程序时,会显示以下的消息


prog3.m:In function‘main’:

prog3.m:13:warning:‘Fraction’does not respond to‘setReal:andImaginary:’


Objective-C编译器知道f1是Fraction的对象,因为它就是这样声明的。编译器同样知道,当遇到消息表达式


[f1 setReal:10.0 andImaginary:2.5];


时,Fraction类并不包含setReal:andImaginary:方法(并且也没有继承该方法),所以生成前面所示的警告消息。

现在考虑下面的代码序列:


id dataValue=[[Fraction alloc]init];

……

[dataValue setReal:10.0 andImaginary:2.5];


这些代码行在编译时,编译器不会产生警告消息。这是因为编译器在处理源文件时并不知道储存在dataValue中的对象的类型。

直到运行包含有这些代码的程序时,才会出现如下的出错消息:


objc:Fraction:does not recognize selector-setReal:andImaginary:

dynamic3:received signal:Abort trap

When attempting to execute the expression

[dataValue setReal:10.0 andImaginary:2.5];


运行时系统首先检查存储在dataValue中的对象类型。因为在dataValue中存储有Fraction,所以运行时系统检查并确定setReal:andImaginary:方法是定义在Fraction类中的一个方法。因为事实并非如此,所以显示前面的出错消息并且终止程序的运行。