【问题标题】:iOS unable to remove Notification observer. Deinit not getting callediOS 无法移除通知观察者。 Deinit 没有被调用
【发布时间】:2017-10-11 16:31:37
【问题描述】:

我有一个类似于您在下面看到的 UIView:

class ViewTaskViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
    super.viewDidLoad()
    subscribeToNotifications()
}

func subscribeToNotifications() {
    let notification = NotificationCenter.default
    notification.addObserver(forName: Notification.Name(rawValue: "TimerUpdated"), object: nil, queue: nil, using: handleUpdateTimer)
    print("Subscribed to NotificationCenter in ViewTaskViewController")
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    print("TUFU TUFU TUFU")
    NotificationCenter.default.removeObserver(self)
}

deinit {
    print("DENINT")
}

@objc func handleUpdateTimer(notification: Notification) {
    if let userInfo = notification.userInfo, let timeInSeconds = userInfo["timeInSeconds"] as? Int {

        withUnsafePointer(to: &self.view) {
            print("We got timeeeeee \(timeInSeconds) \($0)")
        }

       //do something here....
    }
}

}

我遇到的问题是,当用户点击后退按钮并返回到另一个 viewController 时,我无法从这个特定的 UIView 中删除观察者。

ViewWillDisppear 被调用但deinit 未被调用。奇怪的是,如果我们从viewDidLoad() 中删除subscribeToNotifications(),那么会调用deinit

另一个问题与内存泄漏有关。正如您在下面的屏幕截图中看到的,当视图确实订阅了通知并且用户离开/重新进入视图时,内存使用量会增加。

现在比较一下subscribeToNotifications() 被注释掉时,内存使用量没有增加,只有一个viewController 实例。 结论是,通知订阅创建 UIView 的新实例之间似乎存在相关性,因此未调用 deinit

我想知道是否有一种方法可以取消初始化视图并取消订阅通知。

如果您需要更多信息,请告诉我。 :)

【问题讨论】:

  • 您正在使用的 addObserver 方法的文档说:“要取消注册观察,您将 此方法返回的对象传递给 removeObserver(_:)。”相反,您似乎假设 self 是注册对象。

标签: ios swift memory-leaks nsnotification deinit


【解决方案1】:

我发现 removeObserver() 仅在您使用此版本的 addObserver() 时才有效

notification.addObserver(self, selector:#selector(self.handleUpdateTimer), name: Notification.Name(rawValue: "TimerUpdated"), object: nil)

我猜测原始版本实际上并没有表明观察者是谁。

【讨论】:

  • 非常感谢您!我已经尝试了 Khalid 的建议,但仍然没有让它移除观察者。但是您的方法肯定会帮助并解决问题! :)
【解决方案2】:

正如@Spads 所说,您可以使用

NotificationCenter.default.addObserver(self, selector: #selector(subscribeToNotifications), name: NSNotification.Name(rawValue: "TimerUpdate"), object: nil)

或者你已经拥有的那个。 您可以通过它的名称或参考来删除您的通知

NotificationCenter.default.removeObserver(self, name: "TimerUpdate", object: nil)

如果您在班级顶部声明了通知,那么您可以直接传递要在您的案例中删除的通知的引用通知

 NotificationCenter.default.removeObserver(notification)

【讨论】:

  • 所以我确实在提交这个问题之前尝试过,但没有让它发挥作用,尽管添加观察者的另一种方法似乎已经成功了! :) 谢谢
【解决方案3】:

您应该将新添加的观察者存储在不透明对象 (NSObjectProtocol) 中,然后调用 NotificationCenter.default.removeObserver(self.nameOfObserver)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-20
    • 1970-01-01
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多