In the documentation, it says:
The block is copied by the notification center and (the copy) held until the observer registration is removed.
And it provides a one-time observer example code like so:
let center = NSNotificationCenter.defaultCenter()
let mainQueue = NSOperationQueue.mainQueue()
var token: NSObjectProtocol?
token = center.addObserverForName("OneTimeNotification", object: nil, queue: mainQueue) { (note) in
print("Received the notification!")
center.removeObserver(token!)
}
Now I expect the observer to be removed as removeObserver(_:) is called, so my code goes like this:
let nc = NotificationCenter.default
var successToken: NSObjectProtocol?
var failureToken: NSObjectProtocol?
successToken = nc.addObserver(
forName: .ContentLoadSuccess,
object: nil,
queue: .main)
{ (_) in
nc.removeObserver(successToken!)
nc.removeObserver(failureToken!)
self.onSuccess(self, .contentData)
}
failureToken = nc.addObserver(
forName: .ContentLoadFailure,
object: nil,
queue: .main)
{ (_) in
nc.removeObserver(successToken!)
nc.removeObserver(failureToken!)
guard case .failed(let error) = ContentRepository.state else {
GeneralError.invalidState.record()
return
}
self.onFailure(self, .contentData, error)
}
Surprisingly, the self is retained and not removed.
What is going on?
Confirmed some weird behavior going on.
First, I put a breakpoint on the success observer closure, before observers are removed, and printed the memory address of tokens, and
NotificationCenter.default. PrintingNotificationCenter.defaultshows the registered observers.I won't post the log here since the list is very long. By the way,
selfwas captured weakly in the closures.Also confirmed that observers were (supposedly) removed by printing
NotificationCenter.defaultagain after theremoveObserver(_:)s were invoked.Next, I left the view controller and confirmed that the
selfin the quote code was deallocated.Finally, I turned on the debug memory graph and searched for the memory addresses and found this:
In the end, there was no retain cycle. It was just that the observers were not removed, and because the closures were alive, the captured
selfwas alive beyond its life cycle.Please comment if you guys think this is a bug. According to the documentation on
NotificationCenter, it most likely is...