faceterteam / PayCards_iOS

Credit card scanning for mobile apps
https://pay.cards/
Other
199 stars 53 forks source link

UI API called from background thread warnings #48

Open MightyFine opened 4 years ago

MightyFine commented 4 years ago

I've found that if you use the PayCardsRecognizer and set up the UI programmatically, you get "UI API called on a background thread" warnings intermittently, probably like 1/5 times, when presenting the view controller.

The warning stack trace is:

=================================================================
Main Thread Checker: UI API called on a background thread: -[UIView layer]
PID: 20583, TID: 4297841, Thread name: (none), Queue name: com.sunsetlakesoftware.GPUImage.openGLESContextQueue, QoS: 0
Backtrace:
4   PayCardsRecognizer                  0x0000000108781a50 -[GPUImageView createDisplayFramebuffer] + 188
5   PayCardsRecognizer                  0x0000000108781be4 -[GPUImageView setDisplayFramebuffer] + 48
6   PayCardsRecognizer                  0x0000000108781f50 __44-[GPUImageView newFrameReadyAtTime:atIndex:]_block_invoke + 72
7   PayCardsRecognizer                  0x000000010875633c runSynchronouslyOnVideoProcessingQueue + 100
8   PayCardsRecognizer                  0x0000000108781efc -[GPUImageView newFrameReadyAtTime:atIndex:] + 68
9   PayCardsRecognizer                  0x00000001086cafec -[GPUImageVideoCamera updateTargetsForVideoCameraUsingCacheTextureAtWidth:height:time:] + 960
10  PayCardsRecognizer                  0x00000001086cb584 -[GPUImageVideoCamera processVideoSampleBuffer:] + 1316
11  PayCardsRecognizer                  0x00000001086cba50 __74-[GPUImageVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:]_block_invoke + 124
12  libdispatch.dylib                   0x000000010a11a338 _dispatch_call_block_and_release + 24
13  libdispatch.dylib                   0x000000010a11b730 _dispatch_client_callout + 16
14  libdispatch.dylib                   0x000000010a122740 _dispatch_lane_serial_drain + 744
15  libdispatch.dylib                   0x000000010a1232e0 _dispatch_lane_invoke + 444
16  libdispatch.dylib                   0x000000010a12e6c4 _dispatch_workloop_worker_thread + 1304
17  libsystem_pthread.dylib             0x00000001b3638b74 _pthread_wqthread + 272
18  libsystem_pthread.dylib             0x00000001b363b740 start_wqthread + 8
2020-09-17 10:00:37.740128+1000 MyProjectName[20583:4297841] [reports] Main Thread Checker: UI API called on a background thread: -[UIView layer]
PID: 20583, TID: 4297841, Thread name: (none), Queue name: com.sunsetlakesoftware.GPUImage.openGLESContextQueue, QoS: 0
Backtrace:
4   PayCardsRecognizer                  0x0000000108781a50 -[GPUImageView createDisplayFramebuffer] + 188
5   PayCardsRecognizer                  0x0000000108781be4 -[GPUImageView setDisplayFramebuffer] + 48
6   PayCardsRecognizer                  0x0000000108781f50 __44-[GPUImageView newFrameReadyAtTime:atIndex:]_block_invoke + 72
7   PayCardsRecognizer                  0x000000010875633c runSynchronouslyOnVideoProcessingQueue + 100
8   PayCardsRecognizer                  0x0000000108781efc -[GPUImageView newFrameReadyAtTime:atIndex:] + 68
9   PayCardsRecognizer                  0x00000001086cafec -[GPUImageVideoCamera updateTargetsForVideoCameraUsingCacheTextureAtWidth:height:time:] + 960
10  PayCardsRecognizer                  0x00000001086cb584 -[GPUImageVideoCamera processVideoSampleBuffer:] + 1316
11  PayCardsRecognizer                  0x00000001086cba50 __74-[GPUImageVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:]_block_invoke + 124
12  libdispatch.dylib                   0x000000010a11a338 _dispatch_call_block_and_release + 24
13  libdispatch.dylib                   0x000000010a11b730 _dispatch_client_callout + 16
14  libdispatch.dylib                   0x000000010a122740 _dispatch_lane_serial_drain + 744
15  libdispatch.dylib                   0x000000010a1232e0 _dispatch_lane_invoke + 444
16  libdispatch.dylib                   0x000000010a12e6c4 _dispatch_workloop_worker_thread + 1304
17  libsystem_pthread.dylib             0x00000001b3638b74 _pthread_wqthread + 272
18  libsystem_pthread.dylib             0x00000001b363b740 start_wqthread + 8
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIView bounds]
PID: 20583, TID: 4297841, Thread name: (none), Queue name: com.sunsetlakesoftware.GPUImage.openGLESContextQueue, QoS: 0
Backtrace:
4   PayCardsRecognizer                  0x0000000108781b0c -[GPUImageView createDisplayFramebuffer] + 376
5   PayCardsRecognizer                  0x0000000108781be4 -[GPUImageView setDisplayFramebuffer] + 48
6   PayCardsRecognizer                  0x0000000108781f50 __44-[GPUImageView newFrameReadyAtTime:atIndex:]_block_invoke + 72
7   PayCardsRecognizer                  0x000000010875633c runSynchronouslyOnVideoProcessingQueue + 100
8   PayCardsRecognizer                  0x0000000108781efc -[GPUImageView newFrameReadyAtTime:atIndex:] + 68
9   PayCardsRecognizer                  0x00000001086cafec -[GPUImageVideoCamera updateTargetsForVideoCameraUsingCacheTextureAtWidth:height:time:] + 960
10  PayCardsRecognizer                  0x00000001086cb584 -[GPUImageVideoCamera processVideoSampleBuffer:] + 1316
11  PayCardsRecognizer                  0x00000001086cba50 __74-[GPUImageVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:]_block_invoke + 124
12  libdispatch.dylib                   0x000000010a11a338 _dispatch_call_block_and_release + 24
13  libdispatch.dylib                   0x000000010a11b730 _dispatch_client_callout + 16
14  libdispatch.dylib                   0x000000010a122740 _dispatch_lane_serial_drain + 744
15  libdispatch.dylib                   0x000000010a1232e0 _dispatch_lane_invoke + 444
16  libdispatch.dylib                   0x000000010a12e6c4 _dispatch_workloop_worker_thread + 1304
17  libsystem_pthread.dylib             0x00000001b3638b74 _pthread_wqthread + 272
18  libsystem_pthread.dylib             0x00000001b363b740 start_wqthread + 8
2020-09-17 10:00:46.642641+1000 MyProjectName[20583:4297841] [reports] Main Thread Checker: UI API called on a background thread: -[UIView bounds]
PID: 20583, TID: 4297841, Thread name: (none), Queue name: com.sunsetlakesoftware.GPUImage.openGLESContextQueue, QoS: 0
Backtrace:
4   PayCardsRecognizer                  0x0000000108781b0c -[GPUImageView createDisplayFramebuffer] + 376
5   PayCardsRecognizer                  0x0000000108781be4 -[GPUImageView setDisplayFramebuffer] + 48
6   PayCardsRecognizer                  0x0000000108781f50 __44-[GPUImageView newFrameReadyAtTime:atIndex:]_block_invoke + 72
7   PayCardsRecognizer                  0x000000010875633c runSynchronouslyOnVideoProcessingQueue + 100
8   PayCardsRecognizer                  0x0000000108781efc -[GPUImageView newFrameReadyAtTime:atIndex:] + 68
9   PayCardsRecognizer                  0x00000001086cafec -[GPUImageVideoCamera updateTargetsForVideoCameraUsingCacheTextureAtWidth:height:time:] + 960
10  PayCardsRecognizer                  0x00000001086cb584 -[GPUImageVideoCamera processVideoSampleBuffer:] + 1316
11  PayCardsRecognizer                  0x00000001086cba50 __74-[GPUImageVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:]_block_invoke + 124
12  libdispatch.dylib                   0x000000010a11a338 _dispatch_call_block_and_release + 24
13  libdispatch.dylib                   0x000000010a11b730 _dispatch_client_callout + 16
14  libdispatch.dylib                   0x000000010a122740 _dispatch_lane_serial_drain + 744
15  libdispatch.dylib                   0x000000010a1232e0 _dispatch_lane_invoke + 444
16  libdispatch.dylib                   0x000000010a12e6c4 _dispatch_workloop_worker_thread + 1304
17  libsystem_pthread.dylib             0x00000001b3638b74 _pthread_wqthread + 272
18  libsystem_pthread.dylib             0x00000001b363b740 start_wqthread + 8

I'm using Cocoapods to install the framework, and interestingly I'm not able to reproduce this issue if I use a storyboard to generate the UI. I noticed that your example project doesn't have this issue, and also uses a storyboard, which appears to work there too. If you want to try reproduce this, the view controller I'm using which runs into the issue is:

import PayCardsRecognizer
import UIKit

protocol CreditCardScanPresenting {
    func scanned(name: String?, number: String?, expiryMonth: String?, expiryYear: String?)
}

final class CreditCardScanViewController: UIViewController {
    private let presenter: CreditCardScanPresenting
    private let cancelBag = CancelBag()

    private let cardScanContainer = UIView()
    private let labelContainer = UIView()
    private let titleLabel = UILabel()
    private let subtitleLabel = UILabel()

    private lazy var recognizer = PayCardsRecognizer(
        delegate: self,
        resultMode: .async,
        container: cardScanContainer,
        frameColor: .theme(.primaryColor)
    )

    init(presenter: CreditCardScanPresenting) {
        self.presenter = presenter
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("Init with coder not supported.")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        prepareLayout()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        navigationController?.navigationBar.shadowImage = UIImage()
        recognizer.startCamera()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        recognizer.stopCamera()
    }
}

private extension CreditCardScanViewController {
    func prepareLayout() {
        prepareNavigationBar()
        prepareCardScanContainer()
        prepareTitleLabel()
        prepareSubtitleLabel()
        prepareLabelContainer()
    }

    private func prepareNavigationBar() {
        navigationItem.largeTitleDisplayMode = .never
        navigationItem.leftBarButtonItem = {
            let item = UIBarButtonItem(image: .asset(.closeIcon), style: .plain)
            item.tintColor = .theme(.primaryColor)
            item.tapPublisher
                .sink { [weak self] in
                    self?.dismiss(animated: true, completion: nil)
                }
                .cancelledBy(cancelBag)
            return item
        }()
    }

    private func prepareCardScanContainer() {
        view.addSubview(cardScanContainer)

        cardScanContainer.constrain([.leading, .trailing], to: view)
        cardScanContainer.topAnchor
            .constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
            .activate()
    }

    private func prepareTitleLabel() {
        titleLabel.text = LocalizationKey.creditCardScanTitle.localized()
        titleLabel.font = .theme(.contentTitle)
        titleLabel.numberOfLines = 0
        titleLabel.textAlignment = .center

        labelContainer.addSubview(titleLabel)

        titleLabel.constrain(
            [.leading, .trailing, .top],
            to: labelContainer,
            constants: [
                .top: .contentPadding,
                .leading: .contentPadding,
                .trailing: -.contentPadding
            ]
        )
    }

    private func prepareSubtitleLabel() {
        subtitleLabel.text = LocalizationKey.creditCardScanSubtitle.localized()
        subtitleLabel.font = .theme(.contentValue)
        subtitleLabel.numberOfLines = 0
        subtitleLabel.textAlignment = .center

        labelContainer.addSubview(subtitleLabel)

        subtitleLabel.constrain(
            [.leading, .trailing, .bottom],
            to: labelContainer,
            constants: [
                .bottom: -.contentPadding,
                .leading: .contentPadding,
                .trailing: -.contentPadding
            ]
        )
        subtitleLabel.topAnchor
            .constraint(equalTo: titleLabel.bottomAnchor, constant: 8)
            .activate()
    }

    private func prepareLabelContainer() {
        view.addSubview(labelContainer)

        labelContainer.constrain([.leading, .trailing, .bottom], to: view)
        labelContainer.topAnchor
            .constraint(equalTo: cardScanContainer.bottomAnchor, constant: 0)
            .activate()
    }
}

extension CreditCardScanViewController: PayCardsRecognizerPlatformDelegate {
    func payCardsRecognizer(_ payCardsRecognizer: PayCardsRecognizer, didRecognize result: PayCardsRecognizerResult) {
        presenter.scanned(
            name: result.recognizedHolderName,
            number: result.recognizedNumber,
            expiryMonth: result.recognizedExpireDateMonth,
            expiryYear: result.recognizedExpireDateYear
        )
    }
}

There's a few custom extensions used there for constraints, but you get the general idea.

I did some Googling too and it looks like a similar issue is appearing here: https://github.com/BradLarson/GPUImage/issues/2512

I'm guessing from the stack trace you guys use the GPUImage library, and might find that useful, I could be misinterpreting it though.

Good luck, and thank you for an awesome card scanning framework!

vitkuzmenko commented 4 years ago

Hello! I will check it.

SlonGL commented 3 years ago

Same situation. Never warnings in the first call. ViewController in which recognizer is deInit() shows that it is deallocated normally. But when call it again (new instance of VC and recognizer in it), it shows:

MY_DEBUG 1: ["deInit: KickSharing.CardRecognizeVC"]

Main Thread Checker: UI API called on a background thread: -[UIView layer] PID: 9330, TID: 3209519, Thread name: (none), Queue name: com.sunsetlakesoftware.GPUImage.openGLESContextQueue, QoS: 0 Backtrace: 4 PayCardsRecognizer 0x0000000103919a50 -[GPUImageView createDisplayFramebuffer] + 188 5 PayCardsRecognizer 0x0000000103919be4 -[GPUImageView setDisplayFramebuffer] + 48 6 PayCardsRecognizer 0x0000000103919f50 44-[GPUImageView newFrameReadyAtTime:atIndex:]_block_invoke + 72 7 PayCardsRecognizer 0x00000001038ee33c runSynchronouslyOnVideoProcessingQueue + 100 8 PayCardsRecognizer 0x0000000103919efc -[GPUImageView newFrameReadyAtTime:atIndex:] + 68 9 PayCardsRecognizer 0x0000000103862fec -[GPUImageVideoCamera updateTargetsForVideoCameraUsingCacheTextureAtWidth:height:time:] + 960 10 PayCardsRecognizer 0x0000000103863584 -[GPUImageVideoCamera processVideoSampleBuffer:] + 1316 11 PayCardsRecognizer 0x0000000103863a50 74-[GPUImageVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:]_block_invoke + 124 12 libdispatch.dylib 0x0000000108ad7ce4 _dispatch_call_block_and_release + 24 13 libdispatch.dylib 0x0000000108ad9528 _dispatch_client_callout + 16 14 libdispatch.dylib 0x0000000108ae05ac _dispatch_lane_serial_drain + 748 15 libdispatch.dylib 0x0000000108ae1234 _dispatch_lane_invoke + 452 16 libdispatch.dylib 0x0000000108aeca5c _dispatch_workloop_worker_thread + 1456 17 libsystem_pthread.dylib 0x00000001f5d225a4 _pthread_wqthread + 272 18 libsystem_pthread.dylib 0x00000001f5d25874 start_wqthread + 8 2020-11-17 12:45:33.516574+0500 KickSharing[9330:3209519] [reports] Main Thread Checker: UI API called on a background thread: -[UIView layer] PID: 9330, TID: 3209519, Thread name: (none), Queue name: com.sunsetlakesoftware.GPUImage.openGLESContextQueue, QoS: 0 Backtrace: 4 PayCardsRecognizer 0x0000000103919a50 -[GPUImageView createDisplayFramebuffer] + 188 5 PayCardsRecognizer 0x0000000103919be4 -[GPUImageView setDisplayFramebuffer] + 48 6 PayCardsRecognizer 0x0000000103919f50 44-[GPUImageView newFrameReadyAtTime:atIndex:]_block_invoke + 72 7 PayCardsRecognizer 0x00000001038ee33c runSynchronouslyOnVideoProcessingQueue + 100 8 PayCardsRecognizer 0x0000000103919efc -[GPUImageView newFrameReadyAtTime:atIndex:] + 68 9 PayCardsRecognizer 0x0000000103862fec -[GPUImageVideoCamera updateTargetsForVideoCameraUsingCacheTextureAtWidth:height:time:] + 960 10 PayCardsRecognizer 0x0000000103863584 -[GPUImageVideoCamera processVideoSampleBuffer:] + 1316 11 PayCardsRecognizer 0x0000000103863a50 74-[GPUImageVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:]_block_invoke + 124 12 libdispatch.dylib 0x0000000108ad7ce4 _dispatch_call_block_and_release + 24 13 libdispatch.dylib 0x0000000108ad9528 _dispatch_client_callout + 16 14 libdispatch.dylib 0x0000000108ae05ac _dispatch_lane_serial_drain + 748 15 libdispatch.dylib 0x0000000108ae1234 _dispatch_lane_invoke + 452 16 libdispatch.dylib 0x0000000108aeca5c _dispatch_workloop_worker_thread + 1456 17 libsystem_pthread.dylib 0x00000001f5d225a4 _pthread_wqthread + 272 18 libsystem_pthread.dylib 0x00000001f5d25874 start_wqthread + 8

Also any call we have next warnings:

2020-11-17 12:45:18.706359+0500 KickSharing[9330:3209619] [Unknown process name] CGImageCreate: invalid image bits/component: 8 bits/pixel 8 alpha info = kCGImageAlphaNoneSkipLast 2020-11-17 12:45:18.718126+0500 KickSharing[9330:3209619] [Unknown process name] CGImageCreate: invalid image bits/component: 8 bits/pixel 24 alpha info = kCGImageAlphaNoneSkipLast 2020-11-17 12:45:18.791503+0500 KickSharing[9330:3209619] [Unknown process name] CGImageCreate: invalid image bits/component: 8 bits/pixel 8 alpha info = kCGImageAlphaNoneSkipLast

Target iOS 13, testing real iPhone X, iOS 14.2

Recognizer added in the project directly as a framework