import Foundation /// Hört auf eine Darwin-Nachricht und meldet sich beim Abräumen wieder ab. /// /// Warum ein eigenes Objekt und nicht einfach ein Feld im Modell: das Modell /// liegt auf dem MainActor, sein `deinit` aber nicht — es dürfte den Beobachter /// dort gar nicht mehr anfassen. Ein Objekt, dessen einzige Aufgabe die /// Anmeldung ist, bindet das Abmelden an genau die richtige Lebensdauer. /// Auf `nil` setzen genügt zum Abmelden. /// /// `@unchecked Sendable` ist hier belegbar und keine Behauptung ins Blaue: /// `handler` wird nach `init` nie mehr geschrieben, und der Rückruf liest ihn /// nur. Andere veränderliche Zustände gibt es nicht. final class DarwinObserver: @unchecked Sendable { private let name: CFString private let handler: @Sendable () -> Void /// - Parameter handler: läuft auf dem Thread, der die Nachricht zustellt — /// nicht zwingend dem Hauptthread. Wer UI anfasst, hüpft selbst hinüber. init(name: String, handler: @escaping @Sendable () -> Void) { self.name = name as CFString self.handler = handler CFNotificationCenterAddObserver( CFNotificationCenterGetDarwinNotifyCenter(), Unmanaged.passUnretained(self).toOpaque(), { _, observer, _, _, _ in guard let observer else { return } // Unretained: der Beobachter wird beim Abmelden entfernt, also // kann hier kein toter Zeiger ankommen — und ein starker // Verweis hielte das Objekt ewig am Leben. Unmanaged.fromOpaque(observer) .takeUnretainedValue().handler() }, self.name, nil, .deliverImmediately) } deinit { CFNotificationCenterRemoveObserver( CFNotificationCenterGetDarwinNotifyCenter(), Unmanaged.passUnretained(self).toOpaque(), CFNotificationName(name), nil) } }