1

В программировании в Objective C, 4е, глава 9, Программа 9.3:Почему может быть использован методToSelector: метод экземпляра для имени класса или объекта класса?

#import "Square.h" 
int main (int argc, char * argv[]) 
{ 
    @autoreleasepool { 
     Square *mySquare = [[Square alloc] init]; 
     ... 
     // respondsTo: 
     if ([mySquare respondsToSelector: @selector (setSide:)] == YES) 
     NSLog (@"mySquare responds to setSide: method"); 
     ... 
     if ([Square respondsToSelector: @selector (alloc)] == YES) 
     NSLog (@"Square class responds to alloc method"); 
     ... 
    } 
    return 0; 
} 

Q1:

Поскольку -respondsToSelector: является методом экземпляра, а не метод класса, поэтому можно было бы использовать его на Square класс напрямую?

Q2:

Книга говорит, что вы можете использовать Square здесь вместо [Square class]. Это только исключительный ярлык, или есть какой-то механизм этого?

Любая помощь была бы действительно оценена! Заранее спасибо!

+0

1. Короткий ответ заключается в том, что, когда он сводится к нему, все они являются селекционерами. 2. Квадрат (верхний регистр) уже является классом, метод 'class' буквально возвращает один и тот же объект. – CodaFi

+2

Q2: «Квадрат» оценивает мета-класс Square, который представляет собой объект, представляющий класс Square. Это экземпляр объекта, поэтому вы можете сообщить об этом. Отправка '+ class' в объект метакласса возвращает себя. – nielsbot

+0

На самом деле, мой выше комментарий отвечает на ваши вопросы :) – nielsbot

ответ

0

// Q1:

С -respondsToSelector: это метод экземпляра, не метод класса, то почему бы это было возможно, чтобы использовать его на площади класса напрямую //

Вы, кажется, это что методы класса нельзя вызывать из методов экземпляра (и наоборот). Напротив, казалось бы, цель метода -ответчикToSelector сделать это, скорее всего, получив класс отправителя с помощью метода -class, а затем запросив, будет ли класс отвечать на селектор и возвращать YES или NO. В более локализованным примера рассмотрим следующее:

-(void)someInstanceMethod{ 
    [MyCurrentClass doClassMethod]; //basic equivalent of [self doClassMethid]; 
} 

прекрасно действует в Objective-C, при условии, MyCurrentClass это все alloc'd и init'ed.

// Q2:

Книга говорит, что вы можете использовать площадь здесь вместо [Square класс]. Является ли это всего лишь исключительным ярлыком или существует какой-либо механизм? //

Полностью избыточен для отправки класса в класс! Это мало смысла, и это лишний лишний код. -классировать только запросы для класса приемника, независимо от того, является ли это экземпляром или объектом класса.

+0

он должен быть + классом на Q2, иначе вызов не будет работать. –

+0

Также отмечу, что методы класса ALSO принадлежат экземплярам, ​​но не имеют приоритета. –

+0

Ваш Q1 полностью упустил вопрос, поэтому вы можете вызвать 'responsesToSelector:' на объект класса. – user102008

-1

Реальная реализация, прямо из NSObject.m как таковой:

- (BOOL)respondsToSelector:(SEL)aSelector { 
     PF_HELLO("") 
     return class_respondsToSelector(isa, aSelector); 
} 

Теперь, я понятия не имею, почему это PF_HELLO("") есть, но, как вы можете видеть, это буквально расспрашивает класса в RUNTIME «Эй, у вас есть метод для этого isa [instance], называемого aSelector?»

И в Objective-C методы класса также относятся к экземплярам, ​​но, однако, принимают более низкий приоритет (метод экземпляра с тем же именем, что и метод класса, вызывается перед методом класса).

Другой аспект динамической типизации Objective-C является то, что id тип фактически объявлен следующим образом:

typedef struct objc_class *Class; 
typedef struct objc_object { 
    Class isa; 
} *id; 

Таким образом, ваш экземпляр объекта, на самом деле, указатель класса. Это означает, что ваши сообщения -ответчикиToSelector также отправляются в класс типа экземпляра. В вашем случае это означает, что -ответчикToSelector отправляется в objc_class FIRST.

Теперь в тестовом случае (прямо из libFoundation), мой ответ был бы подытожить следующим образом:

Test *tst = [Test new]; 

    fail_unless([tst respondsToSelector:@selector(testInstanceMethod)], "-[Test respondsToSelector:] returned NO for a valid instance method (testInstanceMethod)."); 
    fail_if([tst respondsToSelector:@selector(testClassMethod)], "-[Test respondsToSelector:] returned YES for a class method (testInstanceMethod)."); 
    fail_unless([Test respondsToSelector:@selector(testClassMethod)], "+[Test respondsToSelector:] returned NO for a valid class method (testClassMethod)."); 
    fail_if([Test respondsToSelector:@selector(testInstanceMethod)], "+[Test respondsToSelector:] returned YES for an instance method (testInstanceMethod)."); 
    fail_unless([tst respondsToSelector:@selector(init)], "-[Test respondsToSelector:] returned NO for an inherited instance method (-[NSObject init]."); 
    fail_unless([Test respondsToSelector:@selector(alloc)], "+[Test respondsToSelector:] returned NO for an inherited class method (+[NSObject alloc])."); 

    [tst release]; 
+0

Интересно, откуда берутся коды NSObject.m. Понятия не имею, когда Apple открыла исходную структуру Foundation. – ZhangChn

+0

Старые новости, GNUStep и Cocoatron. GNUStep основан на OpenStep, который предшествует Фонду Mac OS X (и исходит из исходного NextStep Foundation). –

+0

Вы имеете в виду, что все методы экземпляра могут выполнять объекты класса? Но ответ @ZhangChn говорит, что на объектах класса могут выполняться только методы экземпляров, определенные в корневом классе. Любая идея об этом противоречии? Благодаря! – PickBoy

4

От Объективный-C Язык программирования, Objects, class, and Messaging,

Для всех объектов, классов и экземпляров необходим интерфейс для системы времени выполнения . Оба объекта класса и экземпляры должны иметь возможность понять их способности и сообщить свое место в иерархии наследования . Это область класса NSObject до обеспечивает этот интерфейс.

Так что методы NSObject не должны быть реализованы дважды: один раз для обеспечивает интерфейс выполнения для экземпляров и снова повторить этот интерфейс для класса объекты- объектов класса приведены специальное разрешение для выполнения методов экземпляра, определенных в корневой класс. Когда объект класса получает сообщение, которое он не может ответить с помощью метода класса , система времени выполнения определяет, есть ли способ экземпляра root , который может ответить. В только методе экземпляра, что объект класса может выполнять это те , определенные в корневом классе и только если нет методы класса, который может сделать работу.

В этом случае NSObject является классом корня. Так как NSObject экземпляры соответствуют NSObject protocol, где определено -respondsToSelector:, большинство объектов класса должны иметь возможность выполнять -respondsToSelector:.

0

В настоящее время Objective C реализует класс как объект экземпляра какого-либо другого класса. Таким образом, класс будет реагировать на определенные методы экземпляра.

4

Q1:

Простой ответ заключается в том, что, в дополнении к методам класса, вы можете вызвать любой метод экземпляров корневого класса (независимо от корневого класса вашего класса есть, в данном случае, NSObject) на объект класса.

Более сложным ответом является то, что объекты класса являются экземплярами метаклассов. В то время как методы экземпляра являются методами экземпляра, которые определены в классе; class методы являются методами объекта класса, которые определены в метаклассе. У каждого класса есть свой метакласс. Наследование метаклассов следует за их классами; т.е. метакласс класса NSString наследуется от метакласса NSObject. В конечном счете, метакласс класса корня наследует от корневого класса; то есть NSObject в метаклассе наследуется от NSObject. Вот почему все методы экземпляра NSObject доступны объектам класса.

Q2:

[Square class] вызывает метод класса +class (это не имеет никакого отношения к -class). +class - это по существу метод идентификации, который просто возвращает вызываемую вещь (как и -self); то есть, если foo является указателем на объект класса, то [foo class] является таким же, как foo.

Таким образом, +class кажется довольно бесполезным; Почему мы используем это? Это связано с тем, что в грамматике языка Objective-C имя класса не является допустимым выражением (в отличие от Smalltalk). Поэтому вы не можете сказать id bar = Square;; который не будет компилироваться. В качестве специального случая в грамматике имя класса допускается вместо получателя в выражении вызова сообщения, и сообщение отправляется объекту класса; т.е. [Square something]. Поэтому, если вы хотите использовать объект класса в любом другом контексте выражения, мы делаем это обходным путем, вызывая метод идентификации, например +class; то есть [Square class] является выражением, которое может использоваться в любом контексте выражения ([Square self] также будет работать, но мы используем [Square class] по соглашению, что является неудачным, поскольку оно путано с -class); мы бы хотели использовать Square, но не можем из-за языка.

В вашем случае это уже приемник в выражении вызова сообщения, поэтому нет необходимости делать [Square class]; Square уже работает там.