0
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 AVPictureInPictureController with AVPictureInPictureControllerContentSource

  • Custom 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:

  1. Navigates to the video detail page

  2. Cleans up PiP resources

  3. 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)
New contributor
SUN GUANGXIN is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.