Почему мы используем [super dealloc], а не [self dealloc] или [object dealloc] - PullRequest
3 голосов
/ 05 июля 2011

Речь идет о классах и объектах в Objective-c.Я не могу разобраться с концепцией [супер сделки].У нас есть класс myClass, который наследуется от NSObject.Он имеет несколько методов и наследует другие методы от родительского класса.Так что у нас есть метод dealloc и здесь.Почему я не могу просто использовать [myInstance dealloc]?Правильно ли я считаю, что мы вызываем метод родительского класса для уничтожения экземпляра класса?Почему так сложно?

Это не обсуждение [выпуска myInstance]. Я согласен с этой концепцией.

Ответы [ 7 ]

8 голосов
/ 05 июля 2011

Уже есть несколько хороших ответов, но я отвечу на вопросы чуть более прямо:

  1. Почему мы пишем [super dealloc]?

    Мы пишем это, потому что именно это уничтожает экземпляр. В противном случае память никогда не будет освобождена.

  2. Почему бы нам не написать [self dealloc]?

    Мы не можем написать это, потому что единственное место, где вы должны когда-либо явно вызывать dealloc, находится внутри dealloc метода. Выполнение [self dealloc] внутри dealloc просто вызовет сам метод, который затем вызовет себя, вызовет себя, вызовет себя и вызовет себя ....

  3. Почему бы нам не написать [myInstance dealloc]?

    Я предполагаю, что myInstance - это просто заполнитель для переменной в другом методе, который указывает на объект, и вы спрашиваете, почему мы не просто вызываем dealloc через эту переменную. Это потому, что вы не знаете, когда объект должен освободить . Весь смысл retain и release состоит в том, чтобы освободить вас от необходимости отслеживать, когда объект готов к уничтожению. Вы просто сохраняете и освобождаете объект должным образом, и когда release вызывается достаточное количество раз, сигнализируя о том, что у объекта больше нет владельцев, которые хотят сохранить ссылку на него, он вызовет dealloc для себя.

7 голосов
/ 05 июля 2011

Ваш вопрос на самом деле является более общим вопросом, который можно удалить из проблемы dealloc.

Переопределяющие методы и когда вам нужно вызвать super.

Иногда, когда вы создаете подклассыВы переопределяете существующий метод.Иногда вы хотите использовать это удобное время для выполнения какого-либо поведения, иногда вы хотите, чтобы родитель не сделал что-то и изменил поведение.

- (void)methodOne {
  // don't let silly parent class do method one stuff

  // do my stuff …
}

- (void)methodTwo {
  // let parent perform his behavior first
  [super methodTwo];

  // do my stuff …
}

- (void)methodThree {
  // do my stuff …

  // let parent do his stuff after I have
  [super methodThree];
}

- (void)methodFour {
  // it's not common, but you might want to split your stuff with a call to
  // super - this usually involves knowledge of what super is up to

  // do some stuff …
  [super methodFour];
  // do my stuff …
}

Возможно, документация для многих методов / классов (см. UIView и NSManagedObject)Скажите, можете ли вы или не должны переопределять методы.Хорошая документация скажет вам, когда вы должны вызывать super.

Когда вы вызываете [super dealloc], вы должны вызывать его последним, после того, как вы освободили ресурсы, на которых удерживали.(поскольку вполне вероятно, что другая память, на которую вы можете ссылаться, будет освобождена вашим родительским классом).

Другой часто вызываемый super находится в методах init.Если вы реализуете метод init, вам следует переопределить «назначенный инициализатор» родителя, и вы должны вызывать super из своего.

@implementation CustomViewController

- (id)init {
  return [super initWithNibName:@"CustomView" bundle:nil];
}

- (id)initWithNibName:(NSString *)name bundle:(NSBundle *)bundle {
  return [self init];
}

//…

Этот общий шаблон не позволяет никому загружать ваш класс с неверным файлом пера.(Это может или не может быть желательным, это другая проблема.)

Если были другие инициализаторы, по определению они должны вызывать назначенный им инициализатор.Поэтому, если бы UIView добавил метод initWithNibName:, он, скорее всего, вызвал бы [self initWithNibName:name bundle:nil], который затем был бы «перехвачен» и перенаправлен на ваш предполагаемый инициализатор.

5 голосов
/ 05 июля 2011

Когда вызывается -dealloc, контракт заключается в том, что он продвигается вверх по иерархии классов, чтобы обеспечить правильное распределение памяти, используемой каждым родительским классом. [self dealloc] вызовет ваш метод снова и даст вам бесконечный цикл. [super dealloc] разрушает все настройки суперкласса - и если этот суперкласс равен NSObject, он также освобождает память, занимаемую объектом.

3 голосов
/ 05 июля 2011

Вы делаете это так:

@interface MyClass : SuperClass
@end

@implementation MyClass

- (void)dealloc
{
    // Release stuff allocated in MyClass
    [super dealloc];
}

@end

Так что это значит? Предположим, у вас есть экземпляр MyClass, и он был выпущен / автоматически выпущен до тех пор, пока его количество сохранений не упадет до 0. Теперь Objective-C хочет уничтожить экземпляр. Чтобы убрать вещи, Objective-C вызывает dealloc метод.

Теперь вызывается dealloc, как определено в MyClass. Но вы вывели класс из какого-то другого класса. А это значит, что у этого суперкласса тоже есть что почистить. Поэтому вы должны вызвать [super dealloc];, что означает: выполнить dealloc, как определено в SuperClass .

Аналогичная концепция применима к вашим init или initFoo методам: в ней вы делаете что-то вроде self = [super init];, чтобы суперкласс мог выполнить свою инициализацию.

Кроме того, вы никогда не должны звонить dealloc напрямую! Он предназначен для вызова Objective-C, только когда пришло время очистить объект.

Кстати, self означает: текущий экземпляр моего объекта , в то время как super означает: текущий экземпляр моего объекта, но использовать методы, определенные суперклассом .

1 голос
/ 05 июля 2011

Короче говоря, это дополнение к инициализатору.Концепция заключается в том, что инициализация распространяется сверху вниз в иерархии наследования, чтобы сначала инициализировать все родительские поля, а освобождение распространяется снизу вверх, чтобы сначала очистить все дочерние поля.В вашем методе init вы всегда вызываете [super init] первым, а в dealloc вы всегда вызываете [super dealloc] последним.Для получения дополнительной информации о [super dealloc], проверьте этот вопрос

0 голосов
/ 05 июля 2011

Использование [self dealloc] в -dealloc приведет к бесконечной рекурсии. Метод -dealloc будет просто вызывать сам себя. Вы не можете использовать [object dealloc] в -dealloc, потому что у вас нет и не должно быть указателя на себя помимо self. Вы правы, что NSObject нужно сделать свою собственную уборку. Все, что создает класс, отвечает за очистку. Кроме того, [super dealloc] должно быть последней строкой -dealloc. В противном случае у вас может не быть выделенного объекта после этой точки.

0 голосов
/ 05 июля 2011

Нет, вы правы.

Родительский класс (в вашем примере NSObject) должен выполнять свои собственные инструкции. Вот почему сразу после написания инструкций по выпуску вы отправляете dealloc в суперкласс, чтобы завершить процесс.

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