Ух ты, сколько полу-правильных ответов и вводящих в заблуждение подсказок Это позволяет мне ответить на вопрос, даже если есть принятый ответ в течение многих лет:
Прежде всего: действительно трудно сравнить концепцию обмена сообщениями / вызова в контексте раннего связывания, языка статической типизации как Java с поздним связыванием, языков динамической типизации как Objective-C. В какой-то момент это сломается. Я бы сказал: нет, это не похоже на то, что концепции типизации и диспетчеризации обоих языков фундаментально различны, поэтому ничто не может быть похожим на другой. Однако ...
Тогда мы должны различать «две стороны» self
.
A. Используя себя
Когда вы используете его в сообщении, это просто ссылка на объект, как и любая другая:
[self doSomething];
[anotherObject doSomething];
Технически, обе линии работают одинаково (конечно, допускается наличие другого получателя). Это особенно означает, что первая строка не приводит к выполнению метода внутри класса self
, потому что self
не обязательно ссылается на "этот класс" , Как и каждое сообщение внутри Objective-C (единственное исключение: сообщения super
), это может привести к выполнению метода в подклассе:
@interface A : NSObject
- (void)doSomething;
- (void)doAnotherThing;
@end
@implementation
- (void)doSomething
{
[self doAntoherThing];
}
- (void)doAnotherThing
{
NSLog( @"A" );
}
@interface B : A
- (void)doSomething; // Not necessary, simply as a marker
@end
@implementation B
- (void)doAnotherThing
{
NSLog( @"B" );
}
В коде, подобном этому
B *b = [B new;]
[b doSomething];
Линия
[self doAnotherThing];
в классе A
приведет к выполнению -doAnotherThing
(B
), поскольку сообщения на self
задерживаются как все остальные сообщения. Результат на консоли будет b "B", а не "A". Используя self
в качестве приемника, вы не должны думать ни об одном специальном правиле. Там полностью нет.
(И приведенный выше пример является очень хорошим примером использования self
в методах класса, потому что такая же ситуация может возникнуть в методах класса. Использование самого класса нарушает полиморфизм, что является одной из худших идей в ООП . DO также использовать self
в методах класса.)
B. Получение self
На что указывает self
? Он указывает на объект, которому отправлено сообщение, вызвавшее выполнение текущего метода.
Имея…
…[someObject doSomething]… // some object is a reference to an instance object
… в качестве сообщения вызывается метод, в самом простом случае…
- (void)doSomething
{ … }
В таком случае self
может указывать на экземпляр класса, которому принадлежит метод. И он может указывать на экземпляр подкласса, к которому относится и метод. Вы не знаете (И эта информация сохраняется с помощью self
для отправки сообщения, как описано выше.)
Если сообщение отправляется объекту класса, self
указывает на объект класса, который был получателем сообщения. Это полностью аналогично. Поэтому возможно, что self
указывает на объект подкласса:
@interface A : NSObject
+ (void)doSomething;
+ (void)doAnotherThing;
@end
@implementation
+ (void)doSomething
{
[self doAntoherThing];
}
+ (void)doAnotherThing
{
NSLog( @"A" );
}
@interface B : A
- (void)doSomething; // Not necessary, simply as a marker
@end
@implementation B
+ (void)doAnotherThing
{
NSLog( @"B" );
}
Наличие этих классов
…[A doSomething]…
self
внутри -doSomething
(A
) указывает на объект класса B
. Поэтому [self doAnotherThing]
из B
(!) Выполняется. Это явно отличается от
+ (void)doSomething
{
[A doAntoherThing];
}
Последняя версия наносит существенный вред принципам ООП.
В качестве примечания, возможно, что self
внутри метода класса корневого класса указывает на объект экземпляра корневого класса или любого подкласса. Об этом следует помнить при написании категорий на NSObject
.