Почему я должен вызывать super -dealloc последним, а не первым?

Правильный пример:

- (void)dealloc {
    [viewController release];
    [window release];
    [super dealloc];
}

неправильный пример:

- (void)dealloc {
    [super dealloc];
    [viewController release];
    [window release];
}

Хотя почти во всех других случаях при переопределении метода я бы сначала вызвал реализацию метода super, в этом случае apple всегда в конце вызывает [super dealloc]. Зачем?

6 ответов

Решение

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

Также KVO и зависимые (запускаемые) ключи могут вызывать побочные эффекты, если они зависят от уже освобожденных переменных-членов.

Я ничего не знаю о программировании для 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();
        }
    }
}

Возможно, вы не столкнетесь с этой проблемой в своем коде, потому что "вы знаете, что делаете", но в целом безопаснее не делать такие вещи.

[super dealloc] освобождает память, используемую вашим объектом, включая указатели на viewController и window. Ссылка на переменные после их освобождения в лучшем случае опасна.

Смотрите этот ответ.

Вот фактический пример, где [super dealloc] должен быть последним, в противном случае вызов removeFromRunLoop вызовет сбой. Я не уверен, что происходит внутри removeFromRunLoop из NSOutputStream, но, похоже, в этом случае он обращается к 'self'.

Настроить:

[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!
}

[к последнему сообщению] Не будет ли tableView, ссылающийся на делегата, отвечать за освобождение своего собственного делегата? Я думаю, что он сохранился, когда установлен (чтобы вы могли выпустить или автоматически выпустить), и он позаботится о себе?

Что касается вопроса OP, я всегда буду вызывать super сначала, если я создаю, и call super last, если я разрушаю. Я думаю об этом как "я хочу, чтобы супер построил то, что он хочет, чтобы я мог опираться на это, и я хочу, чтобы супер разрушали в последнюю очередь после того, как я уберу за собой". Хотя фактически все вызовы, которые я использую, создаются, кроме dealloc, поэтому вы всегда будете видеть это в моем коде dealloc.

У вас практически нет [super dealloc] в конце, потому что это освобождает переменные суперкласса, и к ним больше нельзя получить доступ.

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

Другие вопросы по тегам