Incompatible pointer types initializing 'SubCl

2019-07-06 00:03发布

问题:

In objective-C, why we can not alloc+init or new a base-class object with super-class, whilst we can use constructor of super-class to initialize?

Below is some code :

s1 can be created quite comfortably.

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

But s2 and s3 can not be, and gives a warning

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);

What happens when we break alloc + init to two different statement?

回答1:

The answer can be found in Objective-C Features of the Clang 3.3 documentation:

Related result types

According to Cocoa conventions, Objective-C methods with certain names (“init”, “alloc”, etc.) always return objects that are an instance of the receiving class’s type. Such methods are said to have a “related result type”, meaning that a message send to one of these methods will have the same static type as an instance of the receiver class.

Therefore in

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

the type of the right hand side is actually NSString * and not id, and assigning that to an NSMutableString * gives a "Incompatible pointer types" warning.

On the other hand, the string method in

NSMutableString *s1 = [NSString string];

does not have a "related result type", so it just returns an id which can be assigned to the NSMutableString *.

Breaking alloc/init into separate statements suppresses the warning only if you use id as intermediate type. With NSString or NSMutableString you still get the warnings:

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

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

According to the documentation, a method has a "related result type" if its return type is compatible with the type of its class and if:

  • the first word is “alloc” or “new”, and the method is a class method, or
  • the first word is “autorelease”, “init”, “retain”, or “self”, and the method is an instance method.


回答2:

First case

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

Here you are creating an NSString instance and send init message on it and finally you are assigning an NSString instance to NSMutableString. Here compiler knows that you are assigning an incompatible pointer types. So its warns you.

Second case

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

You are creating an NSString instance and assigned as type id. and send init on an object of type id. id type is generic, compiler doesn't know its actual type till run time(dynamic typing). So it wont warn you. So problem is not in nested call.

Finally its my observation only :).