Swift 4 has runtime errors with code
jld23 opened this issue · comments
This is a great tutorial! I'm stuck on swift 4 syntax changes and I'm hoping you can help.
This line of code in ViewController prepareCamera function
if let availableDevices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back).devices
Has a Buildtime error:
ViewController.swift:34:12: Initializer for conditional binding must have Optional type, not '[AVCaptureDevice]'
I've tried several things and this converted it from an Error to a Warning:
if let availableDevices = try?
AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back).devices
ViewController.swift:53:13: No calls to throwing functions occur within 'try' expression
This also happens with if let previewLayer
in the beginSession function
I was having the same issue, you have to cast your variable in order for it to not have that issue. It looks like this:
if let availableDevices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .back).devices as? [AVCaptureDevice]
Although this error still persists: Conditional cast from 'AVCaptureVideoPreviewLayer' to 'AVCaptureVideoPreviewLayer' always succeeds
Your code will still be able to build and run.
Using XCode Version 9.3.1 (9E501)
A similar (follow on) error occurs in the func beginSession ()
in the section:
if let previewLayer =
It seems to be related but I can't get it working! Any help would be appreciated
Initializer for conditional binding must have Optional type, not 'AVCaptureVideoPreviewLayer'
if let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) {
self.previewLayer = previewLayer
self.view.layer.addSublayer(self.previewLayer)
self.previewLayer.frame = self.view.layer.frame
captureSession.startRunning()
I'm having the same problem with func beginSession() in Xcode 9.4
This setup is not ideal but works for the moment with 9.4.
There is certainly a way to make it work properly, but you can use the mods I made below to at least get past the critical stop and work on other parts of your app development.
So it fixed the problem but states:
Conditional cast from '[AVCaptureDevice]' to '[AVCaptureDevice]' always succeeds.
and
Conditional cast from 'AVCaptureVideoPreviewLayer' to 'AVCaptureVideoPreviewLayer' always succeeds.
Hope it helps!
func prepareCamera() {
captureSession.sessionPreset = AVCaptureSession.Preset.photo
if let availableDevices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video,
// position: .back).devices as? [AVCaptureDevice]{
position: .back).devices as? [AVCaptureDevice]{
captureDevice = availableDevices.first
beginSession()
}
}
func beginSession () {
do {
let captureDeviceInput = try AVCaptureDeviceInput(device: captureDevice)
captureSession.addInput(captureDeviceInput)
}catch {
print(error.localizedDescription)
}
if let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) as? AVCaptureVideoPreviewLayer {
self.previewLayer = previewLayer
self.view.layer.addSublayer(self.previewLayer)
self.previewLayer.frame = self.view.layer.frame
captureSession.startRunning()
let dataOutput = AVCaptureVideoDataOutput()
dataOutput.videoSettings = [(kCVPixelBufferPixelFormatTypeKey as NSString):NSNumber(value:kCVPixelFormatType_32BGRA)] as [String : Any]
dataOutput.alwaysDiscardsLateVideoFrames = true
if captureSession.canAddOutput(dataOutput) {
captureSession.addOutput(dataOutput)
}
captureSession.commitConfiguration()
let queue = DispatchQueue(label: "com.brianadvent.captureQueue")
dataOutput.setSampleBufferDelegate(self, queue: queue)
}
}
FWIW, I completed his tutorial and hosted my code here. If you're concerned about any modern Swift issues that have cropped up, you can consult my code to see how I got it to run: https://github.com/hawkins/XCodeSwiftCameraTutorial