NotifcationCenter вызывает сильный референсный цикл - Swift 5 - PullRequest
1 голос
/ 16 января 2020

При использовании NotifcationCenter я получаю сильный эталонный цикл.

Я использую NotificationCenter для наблюдения за вращением устройства. (Хотя некоторые утверждают, что это не лучший способ определения ротации устройства, в настоящее время это, кажется, мой единственный маршрут, так как не используется автоматическое расположение и раскадровка не используется).

deinit {} никогда не вызывается в моем ViewController, даже если я удаляю наблюдателя в viewWillDisappear и viewDidDisappear.

import UIKit

class TestVC: UIViewController {


    deinit {
        print("TestClass Deinit") //not being triggered ever
    }

    @objc private func rotationDetected(sender: Any) {
        print("we rotated")
    }

    override func viewDidDisappear(_ animated: Bool) {
        //NotificationCenter.default.removeObserver(UIDevice.orientationDidChangeNotification)
    }
    override func viewWillDisappear(_ animated: Bool) {
        NotificationCenter.default.removeObserver(UIDevice.orientationDidChangeNotification)
    //NotificationCenter.default.removeObserver(self) //also doesn't work

    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: rotationDetected)

    }
    override func viewDidLoad() {
        super.viewDidLoad()
    }


}

Любые идеи относительно того, почему это происходит и как ее решить?

Также открыты для любых новых идей о том, как определить обнаружение вращения другими способами (хотя не используются ни автопроявление, ни раскадровка).

Для достижения TestVC() Я использовал self.navigationController?.pushViewController(TestVC(), animated: true) в предыдущем ViewController и go назад я использую pop.

Без Observer класс будет корректно deinit.

РАЗРЕШЕНО

Благодаря ответу, отмеченному ниже, Сильный ссылочный цикл удален.

Просто замените NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: rotationDetected)

с

NotificationCenter.default.addObserver(self, selector: #selector(rotationDetected), name: UIDevice.orientationDidChangeNotification, object: nil)

Ответы [ 2 ]

1 голос
/ 16 января 2020

Это должно работать в viewWillDisappear:

NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)

в сочетании с использованием следующего в viewWillAppear:

NotificationCenter.default.addObserver(self, selector: #selector(rotationDetected), name: UIDevice.orientationDidChangeNotification, object: nil)
0 голосов
/ 16 января 2020

Ваш метод удаления наблюдателя неверен, вы должны сделать так:

class TestVC {
    private var observer: Any

    func viewWillAppear() {
        observer = NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: rotationDetected)
    }

    func viewWillDisappear() {
        NotificationCenter.default.removeObserver(observer)
    }
}

, чтобы устранить цикл сильных ссылок, используйте слабый в замыкании.

...