【问题标题】:ARC not working properly when using NSNotificationCenter使用 NSNotificationCenter 时 ARC 无法正常工作
【发布时间】:2015-12-10 18:05:24
【问题描述】:

为什么不在使用 NSNotificationCenter 的对象上调用 deist,我在下面包含了我的代码的简单版本。在我创建一个观察通知的对象时,当通知被触发时,它会删除观察者的订阅。如果对象被释放,我也会删除订阅。但是,在为应用程序运行分析时,您可以看到 viewDidAppear 完成后,测试对象的持久分配现在为 nil 并且应该已被释放。为什么会这样?

import UIKit

class ViewController: UIViewController {

    var t: test?

    override func viewWillAppear(animated: Bool) {
        t = test()
        fire()
        t = nil
    }

    func fire() {
        NSNotificationCenter.defaultCenter().postNotificationName("Hello",
            object: nil)
    }

}

class test {

    var e: NSObjectProtocol?

    init() {
        e = NSNotificationCenter.defaultCenter().addObserverForName(
            "Hello", object: nil, queue: NSOperationQueue.mainQueue(),
            usingBlock: sayHello)
    }
    deinit {
        if let e = e { NSNotificationCenter.defaultCenter().removeObserver(e) }
    }

    func sayHello(notification: NSNotification) {
        if let e = e { NSNotificationCenter.defaultCenter().removeObserver(e) }
    }

}

即使是在 Objective-C 中,我也会很感激,因为它也可能会回答这个问题。

非常感谢

【问题讨论】:

  • 我给你开美国:IOS没有垃圾收集器。不久前在 OS X 中。
  • 检查addObserverForName的返回类型,所以在这种情况下不是self是观察者。而且我认为您应该在将闭包传递给通知中心时使用[weak self],以免产生保留周期。
  • 您没有正确移除观察者。您的问题的 Objective-C 版本(带答案)在这里:stackoverflow.com/questions/17022714/removeobserver-not-working。
  • 在sayHello中添加e = nil
  • 可能是因为 self 保留在您的 sayHello 块中。你应该使用 [weak self] 或 [unowned self]

标签: ios swift nsnotificationcenter


【解决方案1】:

传入self 的函数作为闭包参数将创建一个保留循环。 你正在做的是有效的简写:

init() {
   e = NSNotificationCenter.defaultCenter().addObserverForName("Hello", object: nil, queue: NSOperationQueue.mainQueue() { notification in 
      self.sayHello(notification) 
   }
}

如您所见,self 正在这里被捕获。为了解决这个问题,您应该在capture list 中将self 定义为unowned:

init() {
   e = NSNotificationCenter.defaultCenter().addObserverForName("Hello", object: nil, queue: NSOperationQueue.mainQueue() { [unowned self] notification in 
      self.sayHello(notification) 
   }
}

这将阻止保留循环。

当您在sayHello 中移除观察者时,您还应该在移除观察者后将e 设置为nil。

在NSNotificationCenter 上使用此方法时,有关保留周期、捕获等的更多信息,请参阅this 问题。

【讨论】:

  • 谢谢这很好用,@Rich 有没有办法传递一个具有弱或无主捕获上下文的函数?避免使用像你的例子中的闭包并保留函数
  • 你可以看看Weakify,否则没有不烦人!
【解决方案2】:

您不会将 self 添加为观察者,而是添加另一个块。

但是

然后你删除自己(虽然从未添加)但忘记了块

--- 所以:

self.observer = center.addObserverForName(didEnterBackground, object: nil, queue: nil) {
   ...
}

后来

center.removeObserver(self.observer)

【讨论】:

    猜你喜欢
    • 2018-10-29
    • 2013-03-03
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 2017-01-24
    • 1970-01-01
    • 2016-12-01
    • 1970-01-01
    相关资源
    最近更新 更多