Swift Academy · Урок

Безопасное удаление наблюдателей

Избегайте утечек и сбоев из-за устаревших наблюдателей.

Урок 3 из 413 шагов

«Безопасное удаление наблюдателей» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Публикация и наблюдение за уведомлениями
  2. Полезные данные уведомлений userInfo
  3. Безопасное удаление наблюдателей
  4. Альтернативы шаблону наблюдателя
← Назад к Swift Academy