Почему мне нужно называть super -dealloc последним, а не первым?
правильный пример:
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
неверный пример:
- (void)dealloc {
[super dealloc];
[viewController release];
[window release];
}
Althoug во всех остальных случаях, когда переопределять метод, я бы сначала назвал реализацию супер метода, в этом случае apple всегда вызывает [super dealloc] в конце. Почему?
Ответы
Ответ 1
Его просто руководство. Вы можете вызвать другие инструкции после [super dealloc]
. однако вы больше не можете обращаться к переменным суперкласса, потому что они выходят, когда вы вызываете [super dealloc]
. Всегда безопасно вызывать суперкласс в последней строке.
Также клавиши KVO и зависимые (инициируемые) могут создавать побочные эффекты, если они зависят от уже выпущенных переменных-членов.
Ответ 2
Я ничего не знаю о программировании для iPhone, но я бы предположил, что по той же причине деструкторы нужно вызывать в обратном порядке. Вы хотите, чтобы весь ваш "мусор" был очищен до вызова вашего суперкласса. Если вы сделаете это, все наоборот может стать беспорядочным. Например, если вашему деструктору необходимо получить доступ к памяти, которую супердеструктор уже освободил:
class X {
private Map foo;
function __construct() {
foo = new Map();
}
function __destruct() {
foo.free;
}
}
class Y extends X {
function __construct() {
super.__construct();
map.put("foo", 42);
}
function __destruct() {
super.__destruct();
if (map.containsKey("foo")) { // boooooooooom!
doSomething();
}
}
}
Вы не можете столкнуться с этой проблемой в своем коде, потому что "вы знаете, что делаете", но это более безопасная и общая практика, чтобы не делать такие вещи.
Ответ 3
[super dealloc] освобождает память, используемую вашим объектом, включая указатели на viewController и окно. Ссылаться на переменные после того, как вы их освободили, в лучшем случае опасно.
См. этот ответ.
Ответ 4
Вот пример, где [super dealloc] должен быть последним, иначе вызов removeFromRunLoop приведет к сбою. Я не уверен, что происходит внутри NSOutputStream removeFromRunLoop, но в этом случае он, похоже, получает доступ к "я".
Настройка:
[outputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
Dealloc:
- (void)dealloc {
if (outputStream) {
[outputStream close];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[outputStream release];
outputStream = nil;
}
delegate = nil;
[super dealloc]; // must be last!
}
Ответ 5
У вас почти почти есть [super dealloc]
в конце, потому что он освобождает переменные суперкласса, и к ним больше нельзя обращаться.
Единственное исключение - если у вас есть подкласс UITableViewController, который использует другой класс в качестве его делегата представления таблиц. В этом случае вам нужно освободить делегат представления таблиц после [super dealloc]
, потому что представление таблицы ссылается на делегат представления таблицы, и сначала открывается представление таблицы.
Ответ 6
[к последнему сообщению] Не будет ли tableView, ссылающийся на делегата, отвечать за освобождение его собственного делегата? Я бы подумал, что он сохранил его при установке (чтобы вы могли освободить его или авторекламу), и он позаботится о себе?
Что касается вопроса OP, я всегда буду называть super первым, если я буду строить, и вызовет super last, если я разрушу. Я думаю об этом как "Я хочу, чтобы супер построить то, что он хочет, чтобы я мог это сделать, и я хочу, чтобы супер срывался последним после того, как я убираюсь после себя". Фактически все вызовы, которые я использую, строят, хотя, кроме dealloc, поэтому вы всегда будете видеть это в моем коде dealloc.