Что такое я в ObjC? Когда я должен использовать это? - PullRequest
6 голосов
/ 21 августа 2009

Что означает self в Objective-C? Когда и где я должен использовать это? Это похоже на this в Java?

Ответы [ 6 ]

14 голосов
/ 21 августа 2009

self относится к экземпляру текущего класса, в котором вы работаете, и да, он аналогичен this в Java.

Вы используете его, если хотите выполнить операцию с текущим экземпляром этого класса. Например, если вы пишете метод экземпляра для класса и хотите вызвать метод этого же экземпляра, чтобы что-то сделать или получить некоторые данные, вы должны использовать self:

int value = [self returnSomeInteger];

Это также часто используется для методов доступа в экземпляре (т. Е. Методов установки и получения), особенно с методами установки, если они реализуют дополнительную функциональность, а не просто устанавливают значение переменной экземпляра, чтобы вам не приходилось повторять повторяйте код, когда вы хотите установить значение этой переменной, например:

[self setSomeVariable:newValue];

Одним из наиболее распространенных вариантов использования self является инициализация класса. Пример кода может выглядеть так:

- (id)init
{
    self = [super init];

    if(self!=nil) {
        //Do stuff, such as initializing instance variables
    }

    return self;
}

Это вызывает инициализатор суперкласса (через super), который представляет собой цепную инициализацию в иерархии классов. Однако возвращаемое значение устанавливается равным self, поскольку инициализатор суперкласса может возвратить объект, отличный от суперкласса.

5 голосов
/ 21 августа 2009

self является подразумеваемым аргументом для всех методов Obj-C, который содержит указатель на текущий объект в методах экземпляра и указатель на текущий класс в методах класса.

Другим подразумеваемым аргументом является _cmd, который является селектором, который был отправлен методу.

Обратите внимание, что вы получаете только self и _cmd в методах Obj-C. Если вы объявите метод C (++), например, как обратный вызов из какой-либо библиотеки C, вы не получите self или cmd.

Дополнительные сведения см. В разделе Использование скрытых аргументов в руководстве по программированию во время выполнения Objective-C.

3 голосов
/ 21 августа 2009

Да, это точно так же, как «this» в Java - оно указывает на «текущий» объект.

2 голосов
/ 21 августа 2009

Два важных примечания:

  1. Сам класс, например UIView (я НЕ говорю о UIView объекте) сам по себе является объектом, и с ним связан self. Так, например, вы можете ссылаться на self в методе класса следующим образом:

    // This works
    +(void) showYourself { [self performSelector: @selector(makeTheMostOfYourself)]; }
    
    // Class method!
    +(void) makeTheMostOfYourself { }
    
  2. Обратите внимание, что компилятор НЕ выдает никаких предупреждений или ошибок, даже если self, на которую вы ссылаетесь, является объектом, а не классом. Вызывать сбои таким способом ОЧЕНЬ легко, например:

    // This will crash!
    +(void) showYourself { [self performSelector: @selector(makeTheMostOfYourself)]; }
    
    // Object method!
    -(void) makeTheMostOfYourself { }
    
    
    
    // This will crash too!
    -(void) showYourself2 { [self performSelector: @selector(makeTheMostOfYourself2)]; }
    
    // Class method!
    +(void) makeTheMostOfYourself2 { }
    

    К сожалению, это затрудняет использование методов класса, что, к сожалению, является ценным инструментом для инкапсуляции посредством сокрытия информации. Просто будь осторожен.

0 голосов
/ 23 октября 2017

Ух ты, сколько полу-правильных ответов и вводящих в заблуждение подсказок Это позволяет мне ответить на вопрос, даже если есть принятый ответ в течение многих лет:

Прежде всего: действительно трудно сравнить концепцию обмена сообщениями / вызова в контексте раннего связывания, языка статической типизации как 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.

0 голосов
/ 21 августа 2009

self - указатель объекта на таблицу диспетчеризации текущих экземпляров. Это неявный первый аргумент для каждой функции-члена объекта, и он назначается при вызове этой функции.

В таких функциях, как init, вам нужно быть осторожным, чтобы при вызове суперкласса init вы переназначали себя на возвращаемое значение, так как суперкласс init может переопределить то, на что указывает self.

super аналогично self, за исключением того, что оно указывает на таблицу диспетчеризации суперкласса.

...