不兼容的指针types,用'BaseClass *'types的expression式初始化'SubClass * __ strong'

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

下面是一些代码:

s1可以很舒适地创build。

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

答案可以在Clang 3.3文档的Objective-C特性中find:

相关的结果types

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

所以在

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

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

另一方面,在string方法中

 NSMutableString *s1 = [NSString string]; 

没有“相关的结果types”,所以它只是返回一个可以分配给NSMutableString *id

将alloc / init分解为单独的语句只有在使用id作为中间types时才会禁止警告。 使用NSStringNSMutableString你仍然得到警告:

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

根据文档,如果一个方法的返回types与它的类的types兼容,并且:

  • 第一个单词是“alloc”或“new”,并且该方法是一个类方法,或者
  • 第一个词是“autorelease”,“init”,“retain”或“self”,方法是一个实例方法。

第一种情况

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

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

第二种情况

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

您正在创build一个NSString实例,并将其指定为typesid 。 并发送一个types为id的对象的initidtypes是通用的,编译器直到运行时才知道它的实际types(dynamictypes)。 所以它不会警告你 。 所以问题不在于嵌套调用。

最后只有我的观察:)。