I'm trying to access the UIApplication.shared.statusBarOrientation
but I keep getting the error UIApplication.statusBarOrientation() must be used from main thread only
:
I tried to add it and the switch statement that uses it to the mainQueue but that leads to the return value
from the function it's contained in to crashing with a nil value:
DispatchQueue.main.async {
let interfaceOrientation = UIApplication.shared.statusBarOrientation
switch interfaceOrientation {
case .portrait, .portraitUpsideDown, .unknown:
videoOrientation = .portrait
case .landscapeLeft:
videoOrientation = .landscapeRight
case .landscapeRight:
videoOrientation = .landscapeLeft
@unknown default:
break
}
}
Code:
func videoOrientation() -> AVCaptureVideoOrientation {
var videoOrientation: AVCaptureVideoOrientation!
let orientation: UIDeviceOrientation = UIDevice.current.orientation
switch orientation {
case .faceUp, .faceDown, .unknown:
// ** I tried to add this alone to the mainQueue but the switch statement couldn't access it so then I tried to add the entire switch but that lead to the return value crashing with a nil
let interfaceOrientation = UIApplication.shared.statusBarOrientation
switch interfaceOrientation {
case .portrait, .portraitUpsideDown, .unknown:
videoOrientation = .portrait
case .landscapeLeft:
videoOrientation = .landscapeRight
case .landscapeRight:
videoOrientation = .landscapeLeft
@unknown default:
break
}
case .portrait, .portraitUpsideDown:
videoOrientation = .portrait
case .landscapeLeft:
videoOrientation = .landscapeRight
case .landscapeRight:
videoOrientation = .landscapeLeft
@unknown default:
break
}
return videoOrientation // ** crashes here **
}
I access the return value when pressing the camerButton to record video using AVFoundation. The movieFileOutput
object accesses the videoOrientation on this line movieFileOutput.connection(with: AVMediaType.video)?.videoOrientation = videoOrientation()
:
Code:
let captureSession = AVCaptureSession()
var movieFileOutput = AVCaptureMovieFileOutput()
var videoFileUrlFromCamera: URL?
func startRecording() {
if !captureSession.outputs.contains(movieFileOutput) {
return
}
// Stop recording
if movieFileOutput.isRecording {
stopMovieRecordigShowControls()
} else {
if !captureSession.outputs.contains(movieFileOutput) {
return
}
// Start recording
movieFileOutput.connection(with: AVMediaType.video)?.videoOrientation = videoOrientation()
movieFileOutput.maxRecordedDuration = maxRecordDuration()
videoFileUrlFromCamera = URL(fileURLWithPath: videoFileLocation())
if let videoFileUrlFromCamera = videoFileUrlFromCamera {
movieFileOutput.startRecording(to: videoFileUrlFromCamera, recordingDelegate: self)
}
}
}
How can I fix this?
UPDATE
I also tried to wrap the entire code inside the DispatchQueue but I got a compile error of Cannot return expression of type () to return type AVCaptureVideoOrientation
:
func videoOrientation() -> AVCaptureVideoOrientation {
DispatchQueue.main.async {
var videoOrientation: AVCaptureVideoOrientation!
let orientation: UIDeviceOrientation = UIDevice.current.orientation
switch orientation {
case .faceUp, .faceDown, .unknown:
let interfaceOrientation = UIApplication.shared.statusBarOrientation
switch interfaceOrientation {
case .portrait, .portraitUpsideDown, .unknown:
videoOrientation = .portrait
case .landscapeLeft:
videoOrientation = .landscapeRight
case .landscapeRight:
videoOrientation = .landscapeLeft
@unknown default:
break
}
break
case .portrait, .portraitUpsideDown:
videoOrientation = .portrait
case .landscapeLeft:
videoOrientation = .landscapeRight
case .landscapeRight:
videoOrientation = .landscapeLeft
@unknown default:
break
}
return videoOrientation
}
}
Dispatching the other code in main thread makes the value
var videoOrientation: AVCaptureVideoOrientation!
to be nil
when you return it as the return fires before the switch , it's better to make sure that you call the whole startRecording()
from main thread like
DispatchQueue.main.async {
self.startRecording()
}
As the closure of the permission check runs in a background thread so you need to dispatch the call of the recording inside DispatchQueue.main.async