swiftautomatic-ref-countingswift5notificationcenterstrong-references

NotifcationCenter causing a strong reference cycle - Swift 5


It appears I am getting a Strong Reference Cycle when using the NotifcationCenter.

I am using NotificationCenter to observe the Rotation of the device. (While some would argue this is not the best way to determine the device rotation, this currently seems to be my only route, as no autolayout is being used and storyboard is not being used).

deinit {} is never being called in my ViewController even if I remove the observer in viewWillDisappear and 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()
    }


}

Any ideas as to why this is occurring and how to resolve it?

Also open to any new ideas on how to determine rotation detection else ways (no autolayout or storyboard is being used though).

To reach TestVC() I used self.navigationController?.pushViewController(TestVC(), animated: true) in the previous ViewController and to go back I use the pop.

Without the Observer present, the class will correctly deinit.

RESOLVED

Thanks to the answer marked below the Strong Reference Cycle is removed.

Simply replace NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: rotationDetected)

with

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


Solution

  • This should work in viewWillDisappear:

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

    in combination with using the following in viewWillAppear:

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