dealloc в Свифт

145

Я хотел бы выполнить некоторую очистку в конце срока службы контроллера представления, а именно удалить NSNotificationCenterуведомление. Реализация deallocрезультатов в ошибке компилятора Swift:

Cannot override 'dealloc' which has been marked unavailable

Каков предпочтительный способ выполнить некоторую очистку в конце жизни объекта в Swift?

Кайл Клегг
источник

Ответы:

333
deinit {
    // perform the deinitialization
}

Из документации Swift :

Деинициализатор вызывается непосредственно перед освобождением экземпляра класса. Вы пишете деинициализаторы с ключевым словом deinit, подобно тому, как инициализаторы пишутся с ключевым словом init. Деинициализаторы доступны только для типов классов.

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

Кайл Клегг
источник
45
deinit {
    // perform the deinitialization
}

правильный ответ для Swift "dealloc".

Тем не менее, хорошо отметить в iOS 9, что NSNotificationCenter больше не нужно очищать!

https://developer.apple.com/library/content/releasenotes/Foundation/RN-FoundationOlderNotes/index.html#X10_11Notes

NSNotificationCenter

В OS X 10.11 и iOS 9.0 NSNotificationCenter и NSDistributedNotificationCenter больше не будут отправлять уведомления зарегистрированным наблюдателям, которые могут быть освобождены. Если наблюдатель может быть сохранен как ссылка со слабой нулевой привязкой, основное хранилище будет хранить наблюдатель как слабую ссылку при нулевой настройке, или, если объект не может быть сохранен как слабый (т.е. у него есть собственный механизм сохранения / освобождения, который предотвращает время выполнения) из-за способности хранить объект слабо) он будет хранить объект как неслабую нулевую ссылку. Это означает, что наблюдатели не обязаны отменять регистрацию в своем методе освобождения. Следующее уведомление, которое будет направлено этому наблюдателю, обнаружит обнуленную ссылку и автоматически отменит регистрацию наблюдателя. Если на объект можно ссылаться слабо, уведомления больше не будут отправляться наблюдателю во время освобождения; предыдущее поведение получения уведомлений во время деэллока все еще присутствует в случае неслабых обнулений эталонных наблюдателей. Наблюдатели на основе блоков с помощью метода - [NSNotificationCenter addObserverForName: object: queue: usingBlock] по-прежнему должны быть незарегистрированными, когда они больше не используются, поскольку система все еще сохраняет сильную ссылку на этих наблюдателей. Удаление наблюдателей (либо со слабой ссылкой, либо с нулевой ссылкой) все еще поддерживается. CFNotificationCenterAddObserver не соответствует этому поведению, поскольку наблюдатель не может быть объектом. Наблюдатели на основе блоков с помощью метода - [NSNotificationCenter addObserverForName: object: queue: usingBlock] по-прежнему должны быть незарегистрированными, когда они больше не используются, поскольку система все еще сохраняет сильную ссылку на этих наблюдателей. Удаление наблюдателей (либо со слабой ссылкой, либо с нулевой ссылкой) все еще поддерживается. CFNotificationCenterAddObserver не соответствует этому поведению, поскольку наблюдатель не может быть объектом. Наблюдатели на основе блоков с помощью метода - [NSNotificationCenter addObserverForName: object: queue: usingBlock] по-прежнему должны быть незарегистрированными, когда они больше не используются, поскольку система все еще сохраняет сильную ссылку на этих наблюдателей. Удаление наблюдателей (либо со слабой ссылкой, либо с нулевой ссылкой) все еще поддерживается. CFNotificationCenterAddObserver не соответствует этому поведению, поскольку наблюдатель не может быть объектом.

но обратите внимание на пункты ниже о сильных ссылках, так что вам, возможно, придется беспокоиться об очистке в любом случае ...?

Джеймс
источник
3
Если блок уведомлений не имеет строгой ссылки, вы должны удалить наблюдателя.
TigerCoding
+1 за то, что не надо убирать наблюдателей. Важно знать! Я делаю все ссылки слабыми, поэтому никогда не сталкиваюсь с этим.
n13
2
Кажется, что на блоки уведомлений всегда ссылаются в соответствии с документацией. Итак: если вы используете блоки для обработки ваших уведомлений, вы должны отменить их регистрацию в deinit.
Марсбер
22

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Deinitialization.html

Swift автоматически освобождает ваши экземпляры, когда они больше не нужны, чтобы освободить ресурсы. Swift управляет памятью экземпляров с помощью автоматического подсчета ссылок (ARC), как описано в разделе Автоматический подсчет ссылок. Как правило, вам не нужно выполнять ручную очистку, когда ваши экземпляры освобождаются. Однако, когда вы работаете с собственными ресурсами, вам может потребоваться выполнить дополнительную очистку самостоятельно. Например, если вы создаете пользовательский класс, чтобы открыть файл и записать в него некоторые данные, вам может потребоваться закрыть файл до освобождения экземпляра класса.

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

deinit {
    // perform the deinitialization
}
Варша Виджайваргия
источник
2

Удаление наблюдателя необходимо до освобождения, иначе произойдет сбой. Это можно сделать с помощью

deinit {
    // perform the deinitialization
    print("deinit")

    removeObserver(self, forKeyPath: kSelectedViewControllerKey, context: nil)
    removeObserver(self, forKeyPath: kSelectedIndexKey, context: nil)

}
Spydy
источник
-2

Будьте осторожны при вызове метода из другого класса из deinit, он, вероятно, закончится сбоем

Джеба Моисей
источник
1
Пониженное как это не должно быть обязательно. Из исх. docs : поскольку экземпляр не освобождается до тех пор, пока не будет вызван его деинициализатор, деинициализатор может получить доступ ко всем свойствам экземпляра, к которому он вызван, и может изменить свое поведение на основе этих свойств (например, поиск имени файла, который должен быть закрытым).
Superjos