【问题标题】:NotifcationCenter causing a strong reference cycle - Swift 5NotifcationCenter 导致强引用循环 - Swift 5
【发布时间】:2020-01-16 16:13:44
【问题描述】:

在使用通知中心时,我似乎得到了一个强参考周期。

我正在使用 NotificationCenter 来观察设备的旋转。 (虽然有些人认为这不是确定设备旋转的最佳方式,但目前这似乎是我唯一的途径,因为没有使用自动布局,也没有使用情节提要)。

deinit {} 永远不会在我的 ViewController 中被调用,即使我删除了 viewWillDisappearviewDidDisappear 中的观察者。

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(),我在之前的ViewController 中使用了self.navigationController?.pushViewController(TestVC(), animated: true),然后返回我使用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)

【问题讨论】:

    标签: swift automatic-ref-counting swift5 notificationcenter strong-references


    【解决方案1】:

    这应该在viewWillDisappear 中工作:

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

    结合使用viewWillAppear中的以下内容:

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

    【讨论】:

    • 您是否知道为什么您提供的addObserver 不会导致强引用循环,但来自 OP 的却会?
    • 不知道为什么这在被接受和投票后被否决了。这是正确的答案。 OP 我认为这是因为您在该方法的闭包using block: @escaping (Notification) -> Void) 中隐含地保留了自我
    【解决方案2】:

    你删除观察者的方法不正确,你应该这样做:

    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)
        }
    }
    

    要消除强引用循环,请在闭包中使用弱。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-25
      • 2018-07-22
      • 2014-12-27
      • 1970-01-01
      相关资源
      最近更新 更多