Skip to content

[5.3.2] Main Thread Checker: UI API called on a background thread: -[UIWindowScene screen] when call setVideo() #847

@cpson

Description

@cpson

*Note: I am a Korean, so please understand if my English is not perfect.

Describe the bug
When configuring the picker to open only video files and presenting it, a crash or unexpected behavior occurs. It seems to be caused by UI-related code being executed on a background thread.

config.screens = [.library]
config.library.mediaType = .video

config.hidesBottomBar = false
config.onlySquareImagesFromCamera = false
config.library.isSquareByDefault = false

// Enable video trimming
config.showsVideoTrimmer = true

// No limit for selecting video duration
config.video.libraryTimeLimit = .infinity

// Maximum trimming duration: 60 seconds
config.video.trimmerMaxDuration = 60

// Send original file for server-side encoding
config.video.compression = AVAssetExportPresetPassthrough

To Reproduce
Steps to reproduce the behavior:

  1. Configure the picker with mediaType = .video
  2. Present the picker.
  3. Select a video and try to enter the preview/trimming screen.
  4. The error occurs when the preview is being fetched.

Expected behavior
setVideo and preview generation should run safely on the main thread, as it accesses UI-related APIs.

Screenshots
none

Environment (please complete the following information):

  • Device: iPhone16Pro
  • OS: iOS 26.0.1
  • Xcode Version: 26.0.1
  • Swift Version: 6.0

Installation Type

  • SPM

Possible Cause
I suspect that the following property is accessed off the main thread. Since it touches UIApplication / UIWindowScene / UIScreen, it must be executed on the main thread.

YPImagePickerConfiguration.swift (line 22):

public static var screenWidth: CGFloat {
    var screenWidth: CGFloat = 0
    let windowScene = UIApplication.safeFirstWindowScene
    screenWidth = windowScene?.screen.bounds.width ?? 1.0
    if UIDevice.current.userInterfaceIdiom == .pad && YPImagePickerConfiguration.widthOniPad > 0 {
        screenWidth = YPImagePickerConfiguration.widthOniPad
    }
    return screenWidth
}

This seems to be triggered by the following line inside
setVideo in YPAssetZoomableView.swift, which is called via
mediaManager.imageManager?.fetchPreviewFor(video:):

let screenWidth = YPImagePickerConfiguration.screenWidth

Although changeAsset() is initially called on the main thread, it dispatches the logic to a background queue:

DispatchQueue.global(qos: .userInitiated).async {
    switch asset.mediaType {
    case .image:
        self.v.assetZoomableView.setImage(...)
    case .video:
        self.v.assetZoomableView.setVideo(...)
    ...
}

As a result, self.v.assetZoomableView.setVideo(...) is executed from a background thread. Since this leads to a call to YPImagePickerConfiguration.screenWidth, UIKit APIs are accessed off the main thread, which likely causes the crash or unexpected behavior.

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions