В Objective C можно вызвать методы класса с:
[MyClass aClassMethod];
И можно запросить вид экземпляра с:
[someInstance isKindOfClass:[MyClass class]];
Но, почему мы должны сделать [MyClass class]
, и не просто обеспечивают MyClass
как это:
[someInstance isKindOfClass:MyClass];
Есть ли причина, что компилятор соглашается с обнаружением MyClass
как получатель (тип указателя), но не как аргумент? Действительно ли это - ограничение парсинга языка? Или возможно ограничение компилятора?
Оооо... забавный вопрос. Ответ - с-изм.
Рассмотрим:
@interface MyClass : NSObject
@end
@implementation MyClass
@end
Теперь, допустим, у вас есть:
...
MyClass *m = nil;
...
В этом контексте компилятор видит MyClass
как определение типа. В *
говорится, что переменная m
является указателем на кусок памяти, который содержит один (или много - не забудьте свое указательное фу в Си) экземпляров MyClass
.
Другими словами, MyClass
- это тип.
Но в контексте чего-то вроде:
[someInstance isKindOfClass: x ];
x
должно быть rvalue или, говоря человеческим языком, значение выражения. Тип, однако, не может быть использован в качестве r-значения.
То, что [класс MyClass]
работает, на самом деле является небольшим хаком, как в языке, так и в компиляторе, поскольку грамматика специально позволяет имени типа быть получателем сообщения (быть целью вызова метода).
И, собственно говоря, вы можете сделать:
typedef MyClass Foo;
....
[MyClass class];
[Foo Class];
Все будет работать. Однако вы не можете сделать следующее но сообщение об ошибке просвечивает:
[NSUInteger class];
error: 'NSUInteger' is not an Objective-C class name or alias
Итак, почему бы не сделать специальный регистр везде как голое имя?
Это приводит к слиянию имен типов и rvalues, и вы быстро оказываетесь вынуждены проглотить что-то вроде [foo isKindOfClass: (MyClass)];
, при этом блевая на [foo isKindOfClass: (MyClass *)];
, который затем вторгается на территорию типизации довольно неудобным образом.
Мой ответ на первый взгляд - потому что [MyClass class] возвращает объект типа Class, а MyClass не наследуется от Class...
@yehnan хорошо это передает, но я немного расскажу об этом. Да, компилятор может быть модифицирован для автоматического преобразования идентификатора класса в его применимый Class
в тех местах, где он является аргументом, а не только тогда, когда он является целью сообщения. Но в компиляторе нет особых требований к такой дополнительной сложности (в переводе: медленнее, труднее обнаруживать ошибки кодирования). Не следует слишком часто называть вещи, которые возвращают Class
. Если да, то ваша объектная модель сломана. Проверка классов должна быть последним, отчаянным подходом после того, как все остальное потерпело неудачу (в первую очередь правильная типизация, а затем responseToSelector:
). Так что для такого редкого случая нет смысла усложнять компилятор таким образом.
@John и @ryanprayogo - вы оба в корне неправы. MyClass - это Class, который также является объектом, но не наследуется от NSObject. Objective-C немного странен в этом смысле, но на самом деле он великолепен, когда полностью объяснен (См. здесь). Ответ здесь, однако, как сказал @yehnan, заключается в том, что имя класса может быть либо именем типа для деклараторов и кастов, либо приемником для сообщений. Реализация [MyClass class]
возвращает self (который внутри метода является MyClass). Также, как сказал @yehnan, язык мог бы поддерживать передачу self в качестве аргумента, но просто не поддерживает.
MyClass
не относится к типу Class
.
[MyClass class]
имеет тип Class
.
Если вы знакомы с Java, концепция та же.
java.lang.String
не относится к типу java.lang.Class
java.lang.String.getClass ()
имеет тип java.lang.Class
Я думаю, что MyClass на самом деле является метаклассом. Вы посылаете ему сообщение class, чтобы получить реальный класс (типа Class).
Потому что то, что isKindOfClass
ожидает, это "класс", и это то, что возвращается при вызове: [MyClass class]
Интересно.
В Objective-C имя класса имеет две роли: как тип данных и как объект класса. В качестве имени типа данных вы можете делать такие вещи, как:
MyClass *anObject;
В качестве объекта класса имя класса может обозначать объект класса только как получатель сообщения. Вот почему вы должны использовать
... isKindOfClass:[MyClass class] ...
Однако я не думаю, что это тот ответ, который может удовлетворить ваши потребности. Для меня ответ - «да, то, что вы хотите, вполне правдоподобно. Но в спецификации сказано иное».
Ссылка: Язык программирования Objective-C Стр. 32, раздел: «Имена классов в исходном коде» .