Почему мы должны делать [класс MyClass] в Objective-C? - PullRequest
44 голосов
/ 24 июня 2010

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

[MyClass aClassMethod];

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

[someInstance isKindOfClass:[MyClass class]];

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

[someInstance isKindOfClass:MyClass];

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

Ответы [ 8 ]

41 голосов
/ 24 июня 2010

Ооооо ... забавный вопрос.Ответ - 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 должно быть r-значением или, с точки зрения человека, значением выражения .Тип, однако, не может быть использован в качестве значения r.

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

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

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

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

[NSUInteger class];

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

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

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

7 голосов
/ 24 июня 2010

Интересно.

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

MyClass *anObject;

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

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

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

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

2 голосов
/ 24 июня 2010

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

1 голос
/ 24 июня 2010

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

1 голос
/ 24 июня 2010

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

0 голосов
/ 24 июня 2010

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

0 голосов
/ 24 июня 2010

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

[MyClass class] относится к типу Class.

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

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

java.lang.String.getClass() относится к типу java.lang.Class

0 голосов
/ 24 июня 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...