Какие плюсы и минусы подписки на уведомления (NotificationCenter) в методе viewDidLoad контроллера?

«Какие плюсы и минусы подписки на уведомления (NotificationCenter) в методе viewDidLoad контроллера?» — вопрос из категории UIKit, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Плюсы:

  • Гарантированная подпискаviewDidLoad вызывается один раз за жизненный цикл контроллера, что обеспечивает своевременную регистрацию наблюдателя до появления view на экране.
  • Централизация логики – код подписки и обработки уведомления находится в одном классе, что упрощает понимание.

Недостатки и риски:

  • Утечки памяти – если не отписаться, объект контроллера будет удерживаться NotificationCenter даже после его деаллокации, так как NotificationCenter.default является синглтоном.
  • Нежелательные колбэки – контроллер может получать и обрабатывать уведомления, когда его view не находится на экране (например, находится в стеке навигации, но скрыт другим контроллером).
  • Сложность отладки – при множественных подписках бывает сложно отследить, откуда пришло уведомление и кто на него подписан.

Рекомендуемая практика в UIKit:

class MyViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Подписываемся на уведомление
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(handleDataUpdated(_:)),
                                               name: .dataDidUpdateNotification,
                                               object: nil) // object: nil - слушаем от всех отправителей
    }

    @objc private func handleDataUpdated(_ notification: Notification) {
        guard let newData = notification.userInfo?["data"] as? MyDataModel else { return }
        // Обновляем UI на главном потоке
        DispatchQueue.main.async {
            self.updateUI(with: newData)
        }
    }

    // ОБЯЗАТЕЛЬНО отписываемся в deinit
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

// Расширение для удобства
extension Notification.Name {
    static let dataDidUpdateNotification = Notification.Name("dataDidUpdateNotification")
}

Современная альтернатива (SwiftUI): Использование @EnvironmentObject, @ObservedObject или .onReceive для Publisher, что обеспечивает реактивное связывание данных без ручного управления подписками.