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)