mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-03 12:28:13 +08:00
macos: avoid notification publisher retain cycle (#13094)
Turns out combine's `publisher(for:,object:)` retains the object! We
verified this with a test script shown below. Fix this with a manual
filter. Found by @mustafa0x.
```
import Combine
import Foundation
final class Token {
deinit { print("Token deinitialized") }
}
weak var weakToken: Token?
var publisher: NotificationCenter.Publisher?
// Create scope that will free token.
do {
let token = Token()
weakToken = token
publisher = NotificationCenter.default.publisher(
for: Notification.Name("TestNotification"),
object: token
)
}
print("Retained:", weakToken != nil)
publisher = nil
print("Released:", weakToken == nil)
```
This commit is contained in:
@@ -292,7 +292,13 @@ extension Ghostty {
|
||||
// A drag can emit multiple selection changes. Debounce so screen
|
||||
// readers hear one announcement once the selection settles.
|
||||
accessibilitySelectionCancellable = NotificationCenter.default
|
||||
.publisher(for: .ghosttySelectionDidChange, object: self)
|
||||
// The publisher retains its object, so filtering with a weak capture
|
||||
// avoids a cycle between self and the stored cancellable.
|
||||
.publisher(for: .ghosttySelectionDidChange)
|
||||
.filter { [weak self] notification in
|
||||
guard let self else { return false }
|
||||
return notification.object as AnyObject? === self
|
||||
}
|
||||
.debounce(for: .milliseconds(100), scheduler: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
|
||||
Reference in New Issue
Block a user