публикация значения NSObject по KeyPath с использованием AsyncStream - проблема эталонного цикла

Я использую параллелизм функций Swift. Я создал вспомогательную функцию, которая возвращает AsyncStream со значениями, опубликованными реализациями NSOBject. Вид кода ниже.

      func asyncStreamFor<Root: NSObject, Value> (_ root: Root, keyPath: KeyPath<Root, Value>) -> AsyncStream<Value> {
    
    AsyncStream { continuation in
        let cancellable = root.publisher(for: keyPath, options: [.initial, .new])
            .sink {
                continuation.yield($0)
            }
        
        continuation.onTermination = { @Sendable _ in
            cancellable.cancel()
        }
    }
}

Я пытаюсь использовать его (и ранее использовал его непосредственно с помощью издателя) для таких целей, как наблюдение за свойствами AVPlayer (скорость, статус). Схема использования ниже:

      class Player {
    let avPlayer = AVPlayer()
    var cancellable = Set<AnyCancellable>()
    init() {
        avPlayer.publisher(for: \.status)
            .sink {
                print($0)
            }.store(in: &cancellable)
    }
}

Выпуск экземпляра Player работает правильно (проблем с циклом нет).

Для AsyncStream я попытался упростить и использовать схему, как показано ниже:

      class Player {
    let avPlayer = AVPlayer()
    init() {
        Task {
            for await status in asyncStreamFor(avPlayer, keyPath: \.status) {
                print(status)
            }
        }
    }
}

Здесь, кажется, есть эталонный цикл: экземпляр AsyncStream содержит ссылку на отмену (в закрытии onTermination), которая, в свою очередь, содержит ссылку на avPlayer. Экземпляр игрока не деинициализируется при удалении последней ссылки.

Любая идея, как решить проблему без явной отмены задачи перед удалением ссылки на проигрыватель?

0 ответов

Другие вопросы по тегам