SwiftyCam icon indicating copy to clipboard operation
SwiftyCam copied to clipboard

Camera button pressed before session.isRunning becomes true results in NSInternalInconsistencyException

Open biscottigelato opened this issue 6 years ago • 11 comments

I added some Prints into capturePhotoAsyncronously(). Basically if the function is called before session.isRunning == true, then AVCaptureStillImageOutput will throw an NSInternalInconsistencyException.

DEBUG_USER_ACTION: CameraViewController.capturePressed() #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = capturePressed #line = 51 DEBUG_USER_ACTION: CameraViewController.captureTapped() #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = captureTapped #line = 56 self.session.isRunning: true videoConnection.isEnable: true videoConnection.isActive: true DEBUG_USER_ACTION: didTakePhoto #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = swiftyCam(:didTake:) #line = 183 DEBUG_USER_ACTION: didTakePhoto #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = swiftyCam(:didTake:) #line = 183 2017-08-30 17:17:11.201236-0700 SomeFoodieApp[7915:3469642] Warning: Attempt to present <SomeFoodieApp.MarkupViewController: 0x1088cbb00> on <SomeFoodieApp.CameraViewController: 0x1022d4a00> whose view is not in the window hierarchy! DEBUG_USER_ACTION: CameraViewController.exitPressed() #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = exitPressed #line = 61 DEBUG_USER_ACTION: CameraViewController.capturePressed() #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = capturePressed #line = 51 self.session.isRunning: false videoConnection.isEnable: true videoConnection.isActive: true 2017-08-30 17:17:23.451577-0700 SomeFoodieApp[7915:3469642] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '*** -[AVCaptureStillImageOutput captureStillImageAsynchronouslyFromConnection:completionHandler:] Inconsistent state' *** First throw call stack: (0x188802fe0 0x187264538 0x190252610 0x100dadaec 0x100da86f0 0x100db1508 0x100db153c 0x100db171c 0x100db16d8 0x100da1a88 0x100da1ad8 0x18ef068d0 0x18ef0a104 0x18eac40b4 0x18e965fc4 0x18eefa3a8 0x18eef9f78 0x18eef9224 0x18e964350 0x18e934f80 0x18f12ea20 0x18f12917c 0x18f12945c 0x18f12945c 0x18f12945c 0x1887b142c 0x1887b0d9c 0x1887ae9a8 0x1886deda4 0x18a149074 0x18e999c9c 0x10008f210 0x1876ed59c) libc++abi.dylib: terminating with uncaught exception of type NSException

biscottigelato avatar Aug 31 '17 00:08 biscottigelato

Working around this by disabling the camera button until .AVCaptureSessionDidStartRunning via NoficiationCenter observation. If this is a requirement please add this to the Readme documentation? Thanks!

biscottigelato avatar Aug 31 '17 00:08 biscottigelato

I haven't run into this issue. I was hoping that checking for self.session.isRunning is true before calling captureStillImageAsynchronouslyFromConnection:completionHandler:, but it appears this exception is raised while self.session.isRunning is true. Can you confirm?

Awalz avatar Aug 31 '17 01:08 Awalz

self.session.isRunning is only checked to stop the Preview Layer from appearing. I don't think there's anything within the framework preventing SwiftyCamButton.Tap from being executed?

Basically to reproduce the condition, one just have to keep hammering the camera button as the view is still loading. The odd is the camera session is going to take a while to get running, and SwityCamButton.Tap() will get triggered before isRunning == true

biscottigelato avatar Aug 31 '17 01:08 biscottigelato

If you are running from source, can you try:

fileprivate func capturePhotoAsyncronously(completionHandler: @escaping(Bool) -> ()) {
    
    guard self.session.isRunning == true else {
        print("Cannot take photo while session isn't running")
        return
    }
    ...

    

Awalz avatar Aug 31 '17 01:08 Awalz

Very strange...

DEBUG_USER_ACTION: CameraViewController.capturePressed()  #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = capturePressed #line = 51
Cannot take photo while session isn't running
DEBUG_USER_ACTION: CameraViewController.captureTapped()  #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = captureTapped #line = 56
DEBUG_USER_ACTION: CameraViewController.capturePressed()  #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = capturePressed #line = 51
Cannot take photo while session isn't running
DEBUG_USER_ACTION: CameraViewController.captureTapped()  #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = captureTapped #line = 56
DEBUG_USER_ACTION: CameraViewController.capturePressed()  #file = /Users/biscottigelato/Documents/Dev Space/EatellyApp/SomeFoodieApp/CameraViewController.swift #function = capturePressed #line = 51
self.session.isRunning: true
2017-08-30 19:22:04.014696-0700 SomeFoodieApp[7990:3506864] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '*** -[AVCaptureStillImageOutput captureStillImageAsynchronouslyFromConnection:completionHandler:] Inconsistent state'
*** First throw call stack:
(0x188802fe0 0x187264538 0x190252610 0x100e49a6c 0x100e44868 0x100e4d52c 0x100e4d560 0x100e4d740 0x100e4d6fc 0x100e3dc00 0x100e3dc50 0x18ef068d0 0x18ef0a104 0x18eac40b4 0x18e965fc4 0x18eefa3a8 0x18eef9f78 0x18eef9224 0x18e964350 0x18e934f80 0x18f12ea20 0x18f12917c 0x1887b142c 0x1887b0d9c 0x1887ae9a8 0x1886deda4 0x18a149074 0x18e999c9c 0x10012eac8 0x1876ed59c)
libc++abi.dylib: terminating with uncaught exception of type NSException

biscottigelato avatar Aug 31 '17 02:08 biscottigelato

With my implementation, I was not able to make it crash. Not sure if it's just a pure timing thing... This is inside viewDidLoad()


if let captureButton = captureButton {
      view.bringSubview(toFront: captureButton)
      captureButton.delegate = self
      captureButton.isEnabled = false  // Disable this button until SwiftyCam's AVCaptureSession isRunning == true
    }
    
// Listen to notification of when SwiftyCam's AVCaptureSession isRunning == true
    NotificationCenter.default.addObserver(forName: .AVCaptureSessionDidStartRunning, object: nil, queue: OperationQueue.main) { _ in
      self.captureButton?.isEnabled = true
      NotificationCenter.default.removeObserver(self, name: .AVCaptureSessionDidStartRunning, object: nil)
    }

biscottigelato avatar Aug 31 '17 02:08 biscottigelato

And again, my test method is just basically hammering that capture button as quickly as i can after i pressed from a previous view to launch the camera view.

biscottigelato avatar Aug 31 '17 02:08 biscottigelato

Can you try branch testFix

Awalz avatar Aug 31 '17 03:08 Awalz

Will do, but very swamped at the moment. I'll try to give it a run Saturday.

biscottigelato avatar Aug 31 '17 23:08 biscottigelato

I got this. I browsed through the new delegate and it doesn't seem there's one that indicates that capture session is ready/started?

🔷 User Action - CameraViewController.captureTapped() (CameraViewController.swift:70) 🔷 User Action - CameraViewController.capturePressed() (CameraViewController.swift:65) 🔷 User Action - CameraViewController.captureTapped() (CameraViewController.swift:70) [SwiftyCam]: Cannot take photo. Capture session is not running 🔷 User Action - CameraViewController.capturePressed() (CameraViewController.swift:65) [SwiftyCam]: Cannot take photo. Capture session is not running 🔷 User Action - CameraViewController.captureTapped() (CameraViewController.swift:70) 🔷 User Action - CameraViewController.capturePressed() (CameraViewController.swift:65) 🔷 User Action - CameraViewController.captureTapped() (CameraViewController.swift:70) [SwiftyCam]: Cannot take photo. Capture session is not running

biscottigelato avatar Sep 03 '17 22:09 biscottigelato

I have the same issue and I found the sessions starting place in the "SwiftyCamViewController" and I saw the sessions is starting on the "ViewDidAppear" and if you override the ViewDidAppear and the sessions is not running because the SwiftyCamViewController's ViewDidAppear is not called. Try this. if you use override ViewDidAppear remove and run again.

emrecanozturk avatar Dec 27 '18 20:12 emrecanozturk