【问题标题】:Incompatible pointer types initializing 'SubClass *__strong' with an expression of type'BaseClass *'使用“BaseClass *”类型的表达式初始化“SubClass *__strong”的不兼容指针类型
【发布时间】:2013-03-06 14:09:51
【问题描述】:

在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 分成两个不同的语句时会发生什么?

【问题讨论】:

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


【解决方案1】:

答案可以在 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”,方法是实例方法。

【讨论】:

  • 我应该先检查链接的问题stackoverflow.com/questions/15248437/…!! - 但我独立写了这个答案,没有看到其他问题的答案。
  • @AnoopVaidya:不客气,这是一个有趣的话题。我在研究中学到了一些新东西。
  • 但是我得到了-1的问题:(但我添加了一些新东西:)
  • @AnoopVaidya:你不应该担心一次投反对票——这不值得!
【解决方案2】:

第一种情况

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

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

第二种情况

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

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

最后只是我的观察:)。

【讨论】:

  • alloc 也返回 id,s2 也是如此。
  • alloc 返回一个接收类的新实例,它可以是返回类型为 id 的任何东西。
猜你喜欢
  • 2012-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-17
  • 1970-01-01
相关资源
最近更新 更多