3

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

4

2 回答 2

4

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

相关结果类型

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

因此在

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

右侧的类型实际上是NSString *and not id,并将其分配给 anNSMutableString *会给出“不兼容的指针类型”警告。

另一方面,string方法在

NSMutableString *s1 = [NSString string];

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

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

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”,方法是实例方法。
于 2013-03-06T15:04:22.033 回答
0

第一个案例

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

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

第二种情况

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

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

最后它只是我的观察:)。

于 2013-03-06T14:32:49.230 回答