Безопасное удаление наблюдателей
Избегайте утечек и сбоев из-за устаревших наблюдателей.
«Безопасное удаление наблюдателей» — бесплатный урок Swift Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
Безопасное удаление наблюдателей
Наблюдателей необходимо удалять, когда они больше не нужны. Оставшийся наблюдатель может сработать после уничтожения своего владельца, вызвав ошибки или, в старых API, сбой приложения.
Зачем нужно удаление
Наблюдателей на основе селектора раньше требовалось удалять в deinit, чтобы не отправлять сообщения уже освобождённому объекту.
import Foundation
class Watcher: NSObject {
override init() { super.init() }
deinit { NotificationCenter.default.removeObserver(self) }
}
print("Removes itself on deinit")removeObserver(self)
Вызов removeObserver(self) одним действием отменяет все наблюдения, созданные этим объектом.
import Foundation
class VM: NSObject {
func stop() { NotificationCenter.default.removeObserver(self) }
}
VM().stop()
print("Removed all observations for self")Удаление наблюдения по конкретному имени
Можно удалить только одно наблюдение, передав имя и объект, не затрагивая остальные.
import Foundation
let center = NotificationCenter.default
let obj = NSObject()
let name = Notification.Name("ping")
center.removeObserver(obj, name: name, object: nil)
print("Removed a specific observation")Наблюдатели с token
Замыкание, переданное в addObserver, возвращает непрозрачный token. Сохраните его и удалите наблюдателя с помощью этого token.
import Foundation
let center = NotificationCenter.default
let name = Notification.Name("ping")
let token = center.addObserver(forName: name, object: nil, queue: nil) { _ in }
center.removeObserver(token)
print("Removed via token")Сохранение token
Сохраните token в свойстве, чтобы он существовал столько, сколько требуется наблюдение, и удалите его после завершения работы.
import Foundation
class Model {
var token: NSObjectProtocol?
func start() {
token = NotificationCenter.default.addObserver(
forName: Notification.Name("x"), object: nil, queue: nil) { _ in }
}
func stop() {
if let t = token { NotificationCenter.default.removeObserver(t) }
}
}
let m = Model(); m.start(); m.stop()
print("Lifecycle managed")Автоматическая очистка с помощью deinit
Удаляйте token в deinit, чтобы наблюдение завершалось при освобождении владельца.
import Foundation
class Owner {
var token: NSObjectProtocol?
deinit { if let t = token { NotificationCenter.default.removeObserver(t) } }
}
print("Token removed on deinit")Примечание о времени жизни в современных версиях
В современных средах выполнения наблюдатели, добавленные через блочный API, удаляются автоматически при освобождении token, но явное удаление по-прежнему остаётся безопасным и понятным выбором.
import Foundation
// Holding the token in a property controls its lifetime.
class C { var token: NSObjectProtocol? }
print("Token lifetime equals observation lifetime")Предотвращение циклов удержания
Если замыкание-наблюдатель сильно захватывает self, используйте [weak self], чтобы избежать цикла удержания, препятствующего освобождению памяти.
import Foundation
class VM {
var token: NSObjectProtocol?
func start() {
token = NotificationCenter.default.addObserver(
forName: Notification.Name("x"), object: nil, queue: nil) { [weak self] _ in
self?.handle()
}
}
func handle() { print("handled") }
}
VM().start()Повторное удаление безопасно
Удаление уже отсутствующего наблюдателя безвредно, поэтому защитная очистка не вызовет сбой.
import Foundation
let center = NotificationCenter.default
let obj = NSObject()
center.removeObserver(obj)
center.removeObserver(obj) // no harm
print("Safe to remove twice")Краткое резюме Best-практик
Предпочитайте замыкания с token, сохраняйте token, удаляйте его в deinit и слабо захватывайте self. Так время жизни наблюдения остаётся корректным.
import Foundation
class Best {
var token: NSObjectProtocol?
deinit { token.map { NotificationCenter.default.removeObserver($0) } }
}
print("Followed best practices")Быстрая проверка
Как удалить наблюдателя на основе замыкания, добавленного с помощью addObserver(forName:...)?
Повторение
Всегда удаляйте наблюдателей, которые больше не нужны. Для наблюдателей на основе селектора используйте removeObserver(self), а для наблюдателей на основе замыкания — возвращённый token. Сохраняйте token, выполняйте очистку в deinit и слабо захватывайте self. Далее: сравнение шаблона наблюдателя с альтернативами.
Изучай Swift с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 122
- Уроки
- 409
Часто задаваемые вопросы
Урок «Безопасное удаление наблюдателей» бесплатный?
Да — полный текст урока «Безопасное удаление наблюдателей» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «Безопасное удаление наблюдателей»?
Избегайте утечек и сбоев из-за устаревших наблюдателей. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Безопасное удаление наблюдателей»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Публикация и наблюдение за уведомлениями
- Полезные данные уведомлений userInfo
- Безопасное удаление наблюдателей
- Альтернативы шаблону наблюдателя