使用NSNotificationCenter时,ARC无法正常工作

时间:2015-12-10 09:23:13

标签: ios swift nsnotificationcenter

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

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中我也会很感激,因为它也可能会回答这个问题。

非常感谢

2 个答案:

答案 0 :(得分:5)

传递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问题。

答案 1 :(得分:0)

你不能将自己添加为观察者而是另一个块。

BUT

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

---所以:

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

然后再

center.removeObserver(self.observer)