Last active
February 17, 2021 16:34
-
-
Save ole/5da89bef2c2cb4e0dd0b9e9a881720a7 to your computer and use it in GitHub Desktop.
Demo that retaining self in a NotificationCenter observer block leads to a reference cycle you have to break manually.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Paste into a macOS playground in Xcode and run. | |
// Deleting line 46 "c?.stopObserving()" triggers the assertion because | |
// the reference cycle caused by retaining self in the observer block is never broken. | |
import Foundation | |
let myNotification = NSNotification.Name(rawValue: "myNotification") | |
var cHasBeenDeallocated = false | |
class C { | |
var observer: NSObjectProtocol? | |
init() { | |
print(#function) | |
startObserving() | |
} | |
deinit { | |
print(#function) | |
cHasBeenDeallocated = true | |
stopObserving() | |
} | |
func startObserving() { | |
print("Starting listening to notification") | |
self.observer = NotificationCenter.default.addObserver(forName: myNotification, object: nil, queue: nil) { notification in | |
print("- Received notification:", notification) | |
print("- Retaining self in notification block:", self) | |
} | |
} | |
func stopObserving() { | |
if let observer = self.observer { | |
print("Stopping listening to notification") | |
NotificationCenter.default.removeObserver(observer) | |
self.observer = nil | |
} | |
} | |
} | |
var c: C? = C() | |
NotificationCenter.default.post(name: myNotification, object: nil) | |
// Delete this line to trigger the assertion. deinit is never called because we created a reference cycle. | |
c?.stopObserving() | |
c = nil | |
// If the assertion is triggered, it means we have a reference cycle | |
assert(cHasBeenDeallocated) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment