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类中的一个方法。因为事实并非如此,所以显示前面的出错消息并且终止程序的运行。