不兼容的指针类型使用类型'BaseClass *'初始化'SubClass * __ strong'

时间:2013-03-06 14:09:52

标签: ios objective-c macos compiler-construction clang

在objective-C中,为什么我们不能alloc + initnew具有超类的基类对象,而我们可以使用超类的构造函数来初始化?

以下是一些代码:

s1可以非常舒适地创建。

NSMutableString *s1=[NSString string];
NSLog(@"%@",s1);

s2s3不能,并发出警告

Incompatible pointer types initializing 'SubClass *__strong' with an expression of type'BaseClass *'

NSMutableString *s2=[[NSString alloc] init];
NSLog(@"%@",s2);

NSMutableString *s3=[NSString new];
NSLog(@"%@",s3);

//here no warning.
id mem=[NSString alloc];
NSMutableString *s4=[mem init];
NSLog(@"%@",s4);

当我们将alloc + init分解为两个不同的语句时会发生什么?

2 个答案:

答案 0 :(得分:4)

答案可以在Clang 3.3文档的Objective-C Features中找到:

  

相关结果类型

     

根据Cocoa惯例,具有某些名称的Objective-C方法   (“init”,“alloc”等)总是返回作为实例的对象   接收类的类型。据说这种方法具有“相关性”   结果类型“,意味着发送到这些方法之一的消息将   具有与接收器类的实例相同的静态类型。

因此在

NSMutableString *s2 = [[NSString alloc] init];

右侧的类型实际上是NSString *而不是id,并且将其分配给NSMutableString *会产生“不兼容的指针类型”警告。

另一方面,

中的string方法
NSMutableString *s1 = [NSString string];

没有“相关结果类型”,因此只返回id,可以将其分配给NSMutableString *

仅当您使用id作为中间类型时,将alloc / init分解为单独的语句才会禁止警告。使用NSStringNSMutableString,您仍会收到警告:

NSString *tmp4 = [NSString alloc];
NSMutableString *s4 = [tmp4 init]; // <-- Warning here

NSMutableString *tmp5 = [NSString alloc]; // <-- Warning here
NSMutableString *s5 = [tmp5 init];

根据文档,如果方法的返回类型与其类的类型兼容,并且如果:

,则该方法具有“相关结果类型”。
  • 第一个单词是“alloc”或“new”,方法是类方法,或
  • 第一个单词是“autorelease”,“init”,“retain”或“self”,方法是实例方法。

答案 1 :(得分:0)

第一个案例

   NSMutableString *s2=[[NSString alloc] init];
   NSLog(@"%@",s2);  

您要创建一个NSString实例并在其上发送init消息,最后您将NSString实例分配给NSMutableString。编译器知道您正在分配不兼容的指针类型。所以它警告你。

第二种情况

id mem=[NSString alloc];
NSMutableString *s3=[mem init];  

您正在创建NSString个实例并指定为类型id。并在init类型的对象上发送id id 类型是通用的,编译器直到运行时才知道它的实际类型(动态类型)。所以它不会警告你。所以问题不在于嵌套调用。

最后我的观察结果只是:)。