Несовместимые типы указателей, инициализирующие 'SubClass * __ strong' с выражением типа 'BaseClass *'

В objective-C, почему мы не можем alloc + init или new объект базового класса с суперклассом, в то время как мы можем использовать конструктор суперкласса для инициализации?

Ниже приведен код:

s1 можно создать довольно удобно.

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

Но s2 и s3 не может быть, и выдает предупреждение

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 до двух разных операторов?

Ответ 1

Ответ можно найти в Objective-C Особенности документации Clang 3.3:

Связанные типы результатов

В соответствии с Cocoa соглашениями, Objective-C методы с определенными именами ( "init", "alloc" и т.д.) всегда возвращают объекты, являющиеся экземпляром тип принимающих классов. Говорят, что такие методы имеют result type ", что означает, что сообщение, отправленное на один из этих методов, будет имеют тот же статический тип, что и экземпляр класса приемника.

Поэтому в

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

тип правой стороны на самом деле NSString *, а не id, а присвоение этому значению NSMutableString * дает предупреждение "Несовместимые типы указателей".

С другой стороны, метод string в

NSMutableString *s1 = [NSString string];

не имеет "связанного типа результата", поэтому он просто возвращает id, который может быть назначен NSMutableString *.

Отключение alloc/init в отдельные инструкции подавляет предупреждение только в том случае, если вы используете id как промежуточный тип. С помощью NSString или NSMutableString вы все равно получаете предупреждения:

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

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

Согласно документации, метод имеет "связанный тип результата", если его тип возврата совместим с типом его класса, и если:

  • первое слово - "alloc" или "new", а метод - метод класса, или
  • первым словом является "autorelease", "init", "keep" или "self", а метод - метод экземпляра.

Ответ 2

Первый случай

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

Здесь вы создаете экземпляр NSString и отправляете сообщение init на нем, и, наконец, вы назначаете экземпляр NSString на NSMutableString. Здесь компилятор знает, что вы назначаете несовместимые типы указателей. Поэтому он предупреждает вас.

Второй случай

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

Создается экземпляр NSString и назначается как тип id. и отправьте init на объект типа id. id тип является общим, компилятор не знает его фактического типа до времени выполнения (динамическая типизация). Поэтому он не будет предупреждать вас. Поэтому проблема не в вложенном вызове.

Наконец, мое наблюдение только:).