Подтвердить что ты не робот

Почему мы должны делать [класс MyClass] в Objective-C?

В Objective-C вы можете вызвать методы класса с помощью:

[MyClass aClassMethod];

И вы можете запросить тип экземпляра с помощью:

[someInstance isKindOfClass:[MyClass class]];

Но зачем нам делать [MyClass class], а не просто предоставлять MyClass следующим образом:

[someInstance isKindOfClass:MyClass];

Есть ли причина, по которой компилятор в порядке, столкнувшись с MyClass в качестве получателя (тип указателя), но не как аргумент? Это ограничение для разбора языка? Или, возможно, ограничение компилятора?

4b9b3361

Ответ 1

Ооооо... забавный вопрос. Ответ - это c-ism.

Рассмотрим:

@interface MyClass : NSObject
@end
@implementation MyClass
@end

Теперь, скажем, у вас есть:

...
MyClass *m = nil;
...

В этом контексте компилятор видит MyClass как определение типа. * говорит, что переменная m является pointer to a hunk o' memory that contains one (or many -- don't forget your C pointer-fu) MyClass instances.

Другими словами, MyClass является типом.

Но в контексте чего-то вроде:

[someInstance isKindOfClass: x ];

x должно быть rvalue или, с точки зрения человека, значением выражения. Однако тип не может использоваться как rvalue.

То, что [MyClass class] работает, на самом деле является немного взломанным, как на языке, так и на компиляторе, в том, что грамматика специально разрешает имя типа быть приемником сообщений (быть целью вызова метода).

И, по сути, вы можете сделать:

typedef MyClass Foo;
....
[MyClass class];
[Foo Class];

Все будет работать. Однако вы не можете сделать следующее, но загорается сообщение об ошибке:

[NSUInteger class];

ошибка: "NSUInteger не является именем класса Objective-C или псевдонимом


Теперь, почему бы и нет специального случая повсюду в качестве голого имени?

Это объединяет имена типов и rvalues, и вам быстро приходится проглатывать что-то вроде [foo isKindOfClass: (MyClass)];, пока barfing на [foo isKindOfClass: (MyClass *)];, который затем посягает на территорию моделирования довольно неудобно.

Ответ 2

Интересно.

В Objective-C имя класса имеет две роли, как тип данных и как объект класса. В качестве имени типа данных вы можете делать такие вещи, как:

MyClass *anObject;

В качестве объекта класса имя класса может стоять за объект класса только как приемник сообщений. И вот почему вы должны использовать

... isKindOfClass:[MyClass class] ...

Однако я не думаю, что это ответ, который может удовлетворить ваши потребности. Для меня ответ: "да, то, что вы хотите, правдоподобно, но спецификация говорит по-другому".

Ссылка: Язык Objective-C Язык программирования Страница 32, раздел: "Имена классов в исходном коде" .

Ответ 3

@John и @ryanprayogo - вы оба принципиально ошибаетесь. MyClass - это класс, который также является объектом, но не наследуется от NSObject. Objective-C выглядит странно таким, но на самом деле блестяще, когда полностью объясняется (см. здесь). Ответ здесь, однако, заключается в том, что @yehnan сказал, что имя класса может быть либо типом имени для деклараторов и приведения, либо как приемник для сообщений. Реализация [MyClass class] возвращает self (то есть внутри метода MyClass). Кроме того, как сказал @yehnan, язык мог поддерживать передачу его в качестве аргумента, хотя он просто этого не делает.

Ответ 4

Мой первый взгляд - это потому, что класс [MyClass] возвращает объект типа Class, а MyClass не наследует Class...

Ответ 5

@yehnan захватывает его хорошо, но я немного расширюсь. Да, компилятор может быть изменен, чтобы автоматически преобразовывать идентификатор класса в его применимый Class в тех местах, где он является аргументом, а не только в том случае, когда он является объектом сообщения. Но в компиляторе не так много запросов на такую ​​дополнительную сложность (в переводе: медленнее, сложнее обнаружить ошибки кодирования). Вы не должны называть вещи, которые возвращают Class очень часто. Если да, то ваша объектная модель сломана. Проверка класса должна быть последним, отчаянным подходом после того, как все остальное потерпело неудачу (в первую очередь правильная типизация, а затем respondsToSelector:). Поэтому для такого редкого события, это не имеет большого смысла, чтобы усложнить компилятор таким образом.

Ответ 6

Потому что ожидаемый isKindOfClass является "классом" и что возвращается из вызова: [MyClass class]

Ответ 7

Я думаю, что MyClass на самом деле является метаклассом. Вы отправляете это сообщение класса, чтобы получить фактический класс (типа Class).

Ответ 8

MyClass не относится к типу Class.

[MyClass class] имеет тип Class.

Если вы знакомы с Java, концепция одинаков.

java.lang.String не относится к типу java.lang.Class

java.lang.String.getClass() имеет тип java.lang.Class