Как удалитьObserver в Swift 5, используя метод замыкания addObserver - PullRequest
2 голосов
/ 21 апреля 2020

Это мой первый пост. Я японский iOS инженер (только что стал в этом месяце).

У меня проблема с removeObserver методом NotificationCenter в Swift 5.

Я добавил наблюдателя в ViewController ( V C) с использованием типа закрытия addObserver. Я хочу удалить этот Observer, когда вызвана деинициализация V C.

Я написал NotificationCenter.default.removeObserver(self) в методе deinit V C. Но, похоже, у меня это не сработало.

В чем проблема ???

Кроме того, если у моего кода есть проблема с утечкой памяти, дайте мне знать, как ее исправить.

Вот фрагмент моего кода.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] notification in

            guard let self = self else { return }
            self.loadWeather(notification.object)
        }
    }

    deinit {
        print(#function)
        print("ViewController died")

        NotificationCenter.default.removeObserver(self)
    }
}

Спасибо, Daichi.

Ответы [ 2 ]

1 голос
/ 23 апреля 2020

addObserver на основе замыканий

Если вы используете вариант addObserver на основе замыканий , токен будет наблюдателем , Центр уведомлений вообще ничего не знает о self в этой ситуации. Документация не очень ясна по этому поводу.

из Twitter

То есть бессмысленно делать: NotificationCenter.default.removeObserver(self)

документы рекомендуют два способа:

Обычный способ

Подписаться как обычно:

let center = NSNotificationCenter.defaultCenter()
let mainQueue = NSOperationQueue.mainQueue()
self.localeChangeObserver = center.addObserverForName(NSCurrentLocaleDidChangeNotification, object: nil, queue: mainQueue) { (note) in
    print("The user's locale changed to: \(NSLocale.currentLocale().localeIdentifier)")
}

Удалить наблюдателя в какой-то момент кода. NotificationCenter.default.removeObserver(self.localeChangeObserver) например, через функцию или в deinit

Одиночная подписка

Удалите наблюдателя сразу после того, как он впервые получит обратный вызов

let center = NSNotificationCenter.defaultCenter()
let mainQueue = NSOperationQueue.mainQueue()
var token: NSObjectProtocol?
token = center.addObserverForName("OneTimeNotification", object: nil, queue: mainQueue) { (note) in
    print("Received the notification!")
    center.removeObserver(token!)
}

addObserver на основе селектора

Если вы используете add на основе селектора, self будет наблюдателем. Следовательно, вы можете сделать:

NotificationCenter.default.removeObserver(self)

Но рекомендуется делать это только внутри deinit, потому что ваш код может быть не единственным кодом, добавляющим наблюдателей, которые включают объект.

0 голосов
/ 21 апреля 2020

Установите объект-наблюдатель на текущий контроллер вида.

С apple do c .s , объект -

Объект, чьи уведомления уведомляет наблюдатель. хочет получить; то есть только уведомления, отправленные этим отправителем, доставляются наблюдателю.

NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification,
                                       object: self,
                                       queue: nil) { [weak self] notification in
    guard let self = self else { return }
    self.loadWeather(notification.object)
}

Удаление наблюдателя из NotificationCenter

deinit {
    NotificationCenter.default.removeObserver(self)
}

ДРУГОЙ ПУТЬ

Вы также можете сделать копию объекта Notification Observer и удалить его из NotificationCenter в deinit.

let notificationCenter = NotificationCenter.default
var loadWeatherObserver: NSObjectProtocol?

override func viewDidLoad() {
    super.viewDidLoad()
    loadWeatherObserver = notificationCenter.addObserver(forName: UIApplication.didBecomeActiveNotification,
                                                         object: nil,
                                                         queue: nil) { [weak self] notification in
        guard let self = self else { return }
        self.loadWeather(notification.object)
    }
}

deinit {
    if (loadWeatherObserver != nil) {
        notificationCenter.removeObserver(loadWeatherObserver!)
    }
}
...