NSKeyValueObservation: невозможно удалить наблюдателя для пути ключа из объекта, поскольку он не зарегистрирован в качестве наблюдателя - PullRequest
0 голосов
/ 24 сентября 2018

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

Невозможно удалить наблюдатель Foundation.NSKeyValueObservation 0xaddress для пути ключа «readyForDisplay» изAVPlayerLayer 0xадрес, потому что он не зарегистрирован как наблюдатель.

Это происходит, когда я освобождаю UIView, который содержит AVPlayerLayer.

Мой init:

private var playerLayer : AVPlayerLayer { return self.layer as! AVPlayerLayer }

init(withURL url : URL) {
    ...
    self.asset = AVURLAsset(url: url)
    self.playerItem = AVPlayerItem(asset: self.asset)
    self.avPlayer = AVPlayer(playerItem: self.playerItem)
    super.init(frame: .zero)
    ...
    let avPlayerLayerIsReadyForDisplayObs = self.playerLayer.observe(\AVPlayerLayer.isReadyForDisplay, options: [.new]) { [weak self] (plLayer, change) in ... }
    self.kvoPlayerObservers = [..., avPlayerLayerIsReadyForDisplayObs, ...]
    ...
    }

Mydeinit, где выдается исключение:

deinit {
    self.kvoPlayerObservers.forEach { $0.invalidate() }
    ...
    NotificationCenter.default.removeObserver(self)
}

Согласно Crashlytics это происходит на iOS 11.4.1 на разных iPhone.

Код, ведущий к deinit, довольно прост:

// Some UIViewController context.
self.viewWithAVLayer?.removeFromSuperview()
self.viewWithAVLayer = nil

Буду признателен за любые мысли о том, почему это происходит.

Я видел этот баг , но мне кажется, что это не причина.

РЕДАКТИРОВАТЬ 1:

Дополнительная информация для потомков.На iOS 10, если я не сделаю недействительной, я получаю воспроизводимый сбой на deinitНа iOS 11 он работает без аннулирования (еще не проверено, если сбой исчезнет, ​​если я не сделаю недействительной и позволю наблюдателям быть deinit редактированными с моим классом).

РЕДАКТИРОВАТЬ 2:

Дополнительноинформация для потомков: я также нашел эту ошибку Swift, которая может быть связана - SR-6795 .

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Я принял ответ matt , но я хочу предоставить больше информации о том, как я на самом деле решил свою проблему.

Мой деинит, который не падает, выглядит так:

if let exception = tryBlock({ // tryBlock is Obj-C exception catcher.
        self.kvoPlayerObservers.forEach { $0.invalidate() };
        self.kvoPlayerObservers.removeAll()
}) {
    remoteLoggingSolution.write(exception.description)
}
... // do other unrelated stuff

В основном я пытаюсь перехватить исключение Obj-C, если оно возникает, и пытаюсь зарегистрировать его удаленно.

У меня есть этот код в производстве в течение последних 2 недель, и с тех пор я не получилни журналы сбоев, ни журналы исключений, поэтому я предполагаю, что предложение matt добавить kvoPlayerObservers.removeAll() было правильным (по крайней мере, для моего конкретного случая).

0 голосов
/ 28 сентября 2018

После

self.kvoPlayerObservers.forEach { $0.invalidate() }

Добавить

self.kvoPlayerObservers.removeAll()

Также мне не нравится эта строка:

self.kvoPlayerObservers = [..., avPlayerLayerIsReadyForDisplayObs, ...]

kvoPlayerObservers должен быть сетом, а выНаблюдатели должны вставлять одного за другим по мере их поступления.

...