AVPlayerItem was deallocated while key value observers were still registered - ios

I am using AVQueuePlayer but it is crashing some times. I am getting this log
AVPlayerItem was deallocated while key value observers were still registered with it.
what is the region for crashing please help me.

If you have added an observer for any key, you have to remove observer. You can do so by adding on the s deinit method
deinit {
<observee>.removeObserver(self, forKeyPath::"<your key>")
}

It seems that you forget to remove observer for your player.
Do you have some code like this? player.addPeriodicTimeObserverForInterval
If so, you need to add this line in deinit method of your controller / object:
player.removeTimeObserver(observer)
Also you maybe forget about this one:
player?.removeObserver(self, forKeyPath: "rate")

Related

Swift NotificationCenter remove observer quickest way

I am adding a number of observers in my viewController -- applicationWillResignActive, applicationDidEnterBackground, and many others. I want to remove self as observer to all registered notifications in one line. My question is whether the following line is enough to do that, or are there issues with this code?
deinit {
NotificationCenter.default.removeObserver(self)
}
#Sh_Khan is right:
NotificationCenter.default.removeObserver(self)
You can get even further, as mentioned in the Apple Documentation:
If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its dealloc method.
So I'm working with this in an app right now and the answer might not be as straightforward.
In the documentation, it does state that for iOS 9 and above you are no longer required to explicitly remove the observer in the deinit/dealloc methods for objects. https://developer.apple.com/documentation/foundation/notificationcenter/1413994-removeobserver
However, it appears that this is only true for selector based notification observers. I'll be referencing this blog post: https://oleb.net/blog/2018/01/notificationcenter-removeobserver/.
If you are using block based observers you must still manually remove the observers.
addObserver(forName:object:queue:using:)
The best general way to do this is to capture the tokens in an array, append them when you add the observer and use them for removal when you deinit/dealloc or otherwise need to remove observer behavior for your object.
in your VC/object properties create an array to store observer 'tokens'
var notifObservers = [NSObjectProtocol]()
Register for a block based notification by capturing the function return object and storing it as a token
let observer = NotificationCenter.default.addObserver(forName: , object: , queue:) { [weak self] notification in
// do a thing here
}
notifObservers.append(observer)
Removal
for observer in notifObservers {
NotificationCenter.default.removeObserver(observer)
}
notifObservers.removeAll()
Yes
NotificationCenter.default.removeObserver(self)
this line is sufficient to remove the vc observation as long as all are added with
NotificationCenter.default.addObserver

Stuck in KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED

I'm using the new Swift 4 API and I'm getting the KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED in a non-deterministic manner. Was anyone able to fix it? The code is pretty simple creating a KVO and storing it in a local variable.
private var rateObservation: NSKeyValueObservation?
rateObservation = player.observe(\AVQueuePlayer.rate, options: [.initial, .new]) { (_, change) in
observer(change.newValue)
}
The answer doesn't make sense to me. But it is the only way that made it work for me.
deinit {
rateObservation?.invalidate()
}
Doesn't make sense because the documentation of the new observation clearly says that we don't need to unregister the notification and that works for almost most of the time but sometimes I got the mentioned exception and when I explicitly invalidated the observer it never throw the exception.

Swift 4 KVO block crash: observed object deallocated while observer was still registered

I started developing my app recently with iOS 11 as target version, because that was the default value. I have now lowered the version to 9.3, because of reasons.
The app is pure swift 4, using the new KVO block thing.
I fixed the few compile-time errors I had with safeAreaInsets and whatnot, and the app built successfully. A quick job. Nice.
I tried running it on an iPhone 7 iOS 10.3.1 Simulator, and lord - it was a train wreck. I guess UITableViewAutomaticDimension wasn't really a thing back in the days.
Anyway, I have fixed most of the layout-issues, but now I'm stuck with a few hard crashes. Everywhere I've used this new KVO it crashes when I navigate back.
My navigation-pushed ViewController is KVO-listening to a field inside an object it holds. When I pop the navigation, the viewController and the object is deallocated, in that order, and the app crashes, giving me this error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7fdf2e724250 of class MyProject.MyObject was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x60800003fd80> (
<NSKeyValueObservance 0x610000050020: Observer: 0x61000006f140, Key path: isSelected, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x6180000595f0>
)'
As far as I can tell, it says that the observed object MyObject was deallocated while there was someone observing the variable isSelected.
This is the oberservation-code in MyViewController that observes MyObject.
var observations:[NSKeyValueObservation] = []
func someFunction() {
observations.removeAll()
let myObject = MyObject(/*init*/)
self.myObject = myObject
observations.append(myObject.observe(\.isSelected, changeHandler: { [weak self] (object, value) in
//Do stuff
}))
}
I was under the impression that this new magic KVO-block-style would solve world peace, but apparently that only applies to iOS 11.
Now, I have tried a few things, but I can't get it to not crash. It happens every single time, and I don't understand why.
Since the crash logs tells me that the observed object is being deallocated while an object is observing it, but I also know that the observing object is deallocated before the observed object, I have tried doing this in the observer:
//In MyViewController
deinit {
observations.forEach({$0.invalidate()})
observations.removeAll()
print("Observers removed")
}
But this doesn't help. I have also done this:
//In MyObject
deinit{
print("MyObject deinit")
}
And when I do the thing - I get the following output:
>Observers removed
>MyObject deinit
>WORLD WAR 5 STACK TRACE
I have also tried
//In MyViewController
deinit{
self.myObject.removeObserver(self, forKeyPath: "isSelected")
}
But I get the output saying Can't remove because it is not registered as an observer. So I guess MyViewController isn't actually the observer that gets attached when using this new KVO.
Why didn't any of this work? Where and when do I have to remove the observers in < iOS11?
It looks like you're running into a bug that I reported about a year ago, but which unfortunately has received very little attention:
https://bugs.swift.org/browse/SR-5752
Since this bug hasn't bitten me in a while, I had hoped that it'd been fixed in the Swift overlay, but I just tried copying my code from the bug report into an iOS project and running it in the 10.3.1 simulator, and sure enough, the crash came back.
You can work around it like this:
deinit {
for eachObservation in observations {
if #available(/*whichever version of iOS fixes this*/) { /* do nothing */ } else {
self.removeObserver(eachObservation, forKeyPath: #keyPath(/*the key path*/))
}
eachObservation.invalidate()
}
observations.removeAll()
}
Make sure you only do this on iOS versions affected by the bug, because otherwise you'll remove an observation that's already been removed, and then that will probably crash. Isn't this fun?

AVPlayer removing observer crash in Swift 2.2

I have a video app that I built a while back in Swift 1 and I've been trying to migrate to Swift 2.2. It all (finally) works apart from a weird crash to do with observers.
func removeObservers()
{
print("REMOVING OBSERVERS")
if ( !self.is_image && self.player != nil ) {
if (self.player?.observationInfo != nil) {
self.player?.removeObserver(self, forKeyPath: "currentItem.status")
self.player?.removeObserver(self, forKeyPath: "readyForDisplay")
}
}
NSNotificationCenter.defaultCenter().removeObserver(self)
}
This worked previously using SwiftTryCatch but with the lines in place crashes with "'Cannot remove an observer for the key path "readyForDisplay" from because it is not registered as an observer.'" OR with that an observer is registered on a deallocated object if I comment it out.
If I add a do { } catch {} to it I get an error that "this does not throw" and it just crashes the same. How do I go about putting this in some form of try-catch format?
In Swift 2, the libs got annoyingly strict about errors that are truly unexpected (which throw) versus errors that the programmer could have prevented (which do not throw, but just crash your app).
(I’m not a fan of this distinction, or at least not of all the specific decisions Apple made about which errors fall in which category. The JSON API verges on the nonsensical in this department. But…we work with the API we’ve got.)
The NSKeyValueObserving docs say:
It is an error to call removeObserver:forKeyPath: if the object has not been registered as an observer.
“It is an error” is Apple code for “you are responsible for never doing this, and if you do, your app will crash in an uncatchable way.”
In these situations, there is usually an API call you can make to check the validity of the thing you’re about to do. However, AFAIK, there’s no KVO API call you can make to ask, “Is X observing key path Y of object Z?” That means you have three options:
Figure out why you’re trying to remove an observer from something you’re not observing, and prevent that using your program’s own internal logic.
Keep a weak instance var for “player I’m observing,” and check that for a match before attempting to remove the observer.
Add self as an observer before removing it. (I’m pretty sure that a redundant add is OK.)
Since you are making a call removeObserver(self) at the end of the method, why cant you uncomment above code? Because removeObserver(self) removes all the observers if registered any. I hope this solves your issue.
NSNotificationCenter.defaultCenter().removeObserver(self)
status is a property of either AVPlayer or AVPlayerItem.
readyForDisplay is a property of AVPlayerLayer

How to view and debug active key value observers

Typical story... inherited a buggy app from a coder that left a year ago.
App uses some funky transition plugins; namely, iCarousel, MPFFlipTransition.
App pops separate browser tabs.
Error is thrown when the browser or a browser tab is closed
Somewhere an observer is getting leaked.
I've added the following code to the class in question, with no luck:
(void)dealloc {
// implement dealloc method/remove
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
How do I trace the app to find where this observer is being set? Can I observe specific memory locations? Can I somehow view the key/value pairs? Thx, Keith <3
Error thrown:
2014-10-03 12:33:20.938 myApp[5299:60b] An instance 0x145661f0 of class DesktopBrowserVC was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x14547300> (
<NSKeyValueObservance 0x14547210: Observer: 0x145550a0, Key path: title, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x14547320>
You could easily find where any observers are added for that key path by searching your project (Cmd+Shift+F) for the string forKeyPath:#"title"
You can also investigate what observers are currently observing your any object at any time by calling the following method:
[NSObject observationInfo]
And as #AaronWojnowski said, make sure you're not confusing Key-Value Observers with NSNotificationCenter observers!

Resources