2015-12-10 18 views
1

爲什麼不堅持使用NSNotificationCenter的對象進行調用,我在下面包含了一個簡單版本的代碼。在創建觀察通知的對象以及通知被觸發時,它將刪除觀察者的訂閱。如果對象被釋放,我也刪除訂閱。但是,在運行應用程序分析時,您可以看到在viewDidAppear完成後,測試對象的持久分配現在爲零,應該已釋放。爲什麼會這樣?使用NSNotificationCenter時ARC無法正常工作

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中我也會很感激,因爲它也可能會回答這個問題。

非常感謝你

+4

我會爲你打開美國:IOS中沒有垃圾回收器。並且在OS X中很久以前。 –

+0

我的意思是說ARC – luis

+0

檢查'addObserverForName'的返回類型,所以在這種情況下''self'不是'obser'。而且我認爲,當您將封閉傳遞給通知中心時,您應該使用'[weak self]',以便沒有保留週期。 –

回答

5

在傳遞作爲閉包參數的self函數將創建一個保留週期。 你在做什麼是有效性短手:

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

正如你可以看到self正在這裏拍攝的。爲了解決這個問題,你應該在一個capture list定義selfunowned

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

這將阻止保留週期。

當您在刪除觀察者後,還應該在sayHello中將e設置爲nil

請參閱this關於保留週期,捕獲等問題的更多信息,請在NSNotificationCenter上使用此方法。

+0

感謝這很好,@Rich是否有一種方法來傳遞一個功能與弱或無主捕獲的上下文?以避免使用像在你的例子中的閉包,並保持功能 – luis

+1

你可以看看[Weakify](https://github.com/klundberg/Weakify),但否則不會有煩人的! – Rich

0

你不會添加自己作爲觀察員,但另一個塊。

然後您將自己(雖然沒有被加入),但忘記了塊

---這樣:

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

後來

center.removeObserver(self.observer) 
+0

我試過,並沒有工作,即時發佈更新 – luis