就拿NSString * testObject = [[NSData alloc]init];作为例子。编译时和运行时的对象分别是什么呢?
编译时被当做NSString 的实例来处理,运行时其isa指向的是[NSData Class],故运行时该实例只能收到NSData的固有实例方法(或者自己写的Category),如果对该实例发送诸如 testObject stringByAppendingString:@"哈哈哈" ,编译时不会报错只会给出黄色警告,但是运行时会直接崩溃,错误信息可能是
-[_NSZeroData stringByAppendingString:]: unrecognized selector sent to instance 0x8946440
故可以看出NSData 在运行时的真实类型是_NSZeroData(这里用的NSData alloc init,这里是个空的NSData,所以是ZeroData,不是说所有的)
如果对该实例发送诸如 testObject
base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength:这类消息,编译器会直接给出红色错误,无法运行,但其实这个实例是有这个方法的。
这里如果改为 id testObject=[[NSData alloc]init];
那么发送NSString 的方法仍然会崩溃,发送NSData的实例方法则完全正常。并且两种情况编译器都不会再给出警告或错误。
这就是运行时语言的特点。