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?
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: