Тип возвращаемого значения отличается в реализации для объективных протоколов C - PullRequest
0 голосов
/ 15 октября 2019

У меня есть протокол, метод которого возвращает NSArray*. В реализации я сделал тип возвращаемого значения этого метода равным NSView*

. Я вижу, что это происходит только в случае указателей класса Objective C, а не в других случаях, таких как возврат void против возврата int.

Я бы ожидал предупреждения компилятора как минимум, но компиляция происходит просто отлично.

@protocol prot <NSObject>

-(NSArray*)array;

@end
@interface impl : NSObject<prot>

@end

@implementation impl

//Should return NSArray. Returns NSView instead
- (NSView *)array
{
    return nil;
}

@end

Ответы [ 2 ]

0 голосов
/ 15 октября 2019

Согласился, что должно выдать предупреждение, но это не так. Частично проблема заключается в том, что все объекты ObjC id во время выполнения, поэтому вы наблюдаете различное поведение для int (что не id). Но это не совсем оправдание. Это ограничение компилятора. Есть множество мест, где не удается отличить типы объектов ObjC. Объекты ObjC типизированы по типу утки, поэтому, пока они отвечают на правильные сообщения, «они работают».

Иногда это приносит пользу;например, NSArray на самом деле является кластером классов, и есть несколько (частных) типов, которые притворяются NSArray, просто реализуя один и тот же интерфейс. Это то, что легко в ObjC, но трудно в Swift. По-прежнему нет оправдания, так как было бы легко получить это преимущество без этого разочаровывающего отсутствия предупреждения компилятора, но оно возвращает нас к тому, как ObjC думает о типах классов.

Это ограничение исправлено в Swift, и еще одно преимуществоя знаю, что это не очень помогает,

0 голосов
/ 15 октября 2019

Перво-наперво:

impl должно быть Implementation, так как имена классов написаны в верхнем регистре верблюдов, а сокращения плохие (TM). Более того, Class - это указатель класса, NSView* и NSArray* - указатели экземпляров.

К вашему Q, даже я немного устал от этого обсуждения (динамическая или статическая типизация, ранняя иПозднее связывание):

A: Почему компилятор должен предупреждать? Оба являются указателями экземпляров, и, возможно, сообщения, отправляемые объекту, поддерживаются обоими. Компилятор не заботится о связывании, это делается во время выполнения.

B: Но это очень небезопасно!

A: Вы когда-нибудь отправляли код с такой ошибкой?

B: Нет. Но по теории это небезопасно.

A: Да, это верно для всех теорий, которые отправляют код, не выполняя его хотя бы один раз.

B: Но вы должны признать, что это более небезопасно, чем проверка типов во время компиляции.

A: Да, теоретически это правда.

B: Так почему вы поддерживаете это?

A: Потому что во многих ситуациях преимущества динамической типизации имеют. И. е. очень просто написать общий код без шаблонов. (Даже иногда их называют дженериками, они по-прежнему глупые шаблоны.) Очень легко разложить ответственность за то, что требует контра-концептуальных расширений в других языках (сигналы и слоты в C ++, делегаты в C #,…). Это очень легкосоздавать отдельные объекты для снижения нагрузки на память. Это очень легко написать ОРИМ. Должен ли я продолжить?

B: Да

A: Это настолько гибко, что вы можете написать целую инфраструктуру AOP на этом языке. Это настолько гибко, что вы можете написать основанную на прототипах инфраструктуру на этом языке.

Однако иногда компилятору легко обнаружить, что что-то вообще не имеет смысла. И иногда компилятор предупреждает об этом. Но во многих случаях компилятор не умнее разработчика.

...