libobjc.A.dylib _objc_retain_x0 16
AVKit -[AVSampleBufferDisplayLayer(AVPictureInPictureSuppport) avkit_sampleBufferDisplayLayerPlayerController] 36
AVKit -[AVSampleBufferDisplayLayer(AVPictureInPictureContentSource) avkit_videoRectInWindow] 116
AVKit -[AVPictureInPicturePlatformAdapter _updateVideoRectInScreenIfNeeded] 88
AVKit -[AVPictureInPicturePlatformAdapter _isFullScreen] 172
AVKit -[AVPictureInPicturePlatformAdapter _updatePictureInPictureShouldStartWhenEnteringBackground] 68
AVKit -[AVPictureInPicturePlatformAdapter updateLayoutDependentBehaviors] 168
AVKit ___105-[AVObservationController startObserving:keyPaths:includeInitialValue:includeChanges:observationHandler:]_block_invoke_2 64
libdispatch.dylib __dispatch_call_block_and_release 32
libdispatch.dylib __dispatch_client_callout 16
libdispatch.dylib __dispatch_main_queue_drain.cold.5 812
libdispatch.dylib __dispatch_main_queue_drain 180
libdispatch.dylib __dispatch_main_queue_callback_4CF 44
CoreFoundation ___CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ 16
CoreFoundation ___CFRunLoopRun 1944
CoreFoundation __CFRunLoopRunSpecificWithOptions 532
GraphicsServices _GSEventRunModal 120
UIKitCore -[UIApplication _run] 792
UIKitCore _UIApplicationMain 336
Error: SIGSEGV (SEGV_ACCERR) - accessing deallocated memory
Question
I'm experiencing a consistent crash in my iOS video app when users restore from Picture-in-Picture (PiP) mode. The crash happens because AVKit's internal async dispatch tries to access an object that has already been deallocated.Has anyone else experienced this issue,How to resolve?
Environment
iOS 26
iPhone models: iPhone 15 Pro, iPhone 16 Pro Max
Using
AVPictureInPictureControllerwithAVPictureInPictureControllerContentSourceCustom video player with
AVSampleBufferDisplayLayer
Problem Description
When users tap the PiP floating window to return to the app, my PiPManager receives the restore callback and:
Navigates to the video detail page
Cleans up PiP resources
Deallocates the manager
The crash occurs 50-100ms after deallocation when AVKit's internal main queue dispatch callback tries to objc_retain an object that no longer exists.
@available(iOS 15.0, *)
class SBPiPManager: NSObject {
private var controller: AVPictureInPictureController
private var playerController: BFCPlayerControllerV2?
private var sampleBufferLayer: AVSampleBufferDisplayLayer?
// Called when user taps PiP window to restore
func restore() {
PiPLogInfo("[SBPiPManager] restore")
// Keep strong references to prevent premature deallocation
let retainedLayer = controller.contentSource?.sampleBufferDisplayLayer
let retainedPlayerController = playerController
// Stop background rendering
if let playback = playerContainer?.context.playback {
playback.setAllowingBackgroundRendering(false)
playback.setAudioPlayingOnly(false)
if playback.playbackState == .paused {
playback.play()
}
}
// Problem: The manager gets deallocated here before AVKit finishes
// its internal async operations
}
func stop(reason: String) {
PiPLogInfo("[SBPiPManager] stop: \(reason)")
// Pre-emptively notify AVKit before stopping
if controller.contentSource != nil {
controller.invalidatePlaybackState()
controller.contentSource = nil
}
if controller.isPictureInPictureActive {
controller.stopPictureInPicture()
}
// Remove from manager list - this triggers deallocation
PictureInPictureCenter.shared.removePiPManager(self)
}
deinit {
PiPLogInfo("[SBPiPManager] deallocated")
// Crash happens 50-100ms after this when AVKit's async callback fires
}
}
// AVPictureInPictureControllerDelegate
extension SBPiPManager: AVPictureInPictureControllerDelegate {
func pictureInPictureController(
_ pictureInPictureController: AVPictureInPictureController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
prepareToRestore()
// Delay to allow UI to appear
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.restore()
completionHandler(true)
}
}
}
Timeline from Logs
13:35:40.710 - PiP restore initiated
13:35:40.719 - prepareToRestore() called
13:35:40.756 - UI restoration begins
13:35:41.021 - restore() completed, stop() called, manager deallocated
13:35:41.117 - CRASH (96ms after deallocation)