init() is unavailable in AVCaptureDeviceInput in Swift 4

Viewed 5892

I have a view controller in my application that shows the back camera like Snapchat and it was worked well in Swift 3, but when I updated to Swift 4, the compiler won't let me run it because of the following error:

init() is unavailable for AVCaptureDeviceInput

This view controller should show the camera without any button or extra things just like Snapchat. So, here is the full view controller code:

import UIKit
import AVFoundation

class cameraViewController: UIViewController , UIImagePickerControllerDelegate , UINavigationControllerDelegate {

var captureSession : AVCaptureSession?

var stillImageOutput : AVCaptureStillImageOutput?

var previewLayer : AVCaptureVideoPreviewLayer?

var imagePicker: UIImagePickerController!

@IBOutlet weak var cameraView: UIView!

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

    previewLayer?.frame = cameraView.bounds
}

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


    captureSession = AVCaptureSession()

    captureSession?.sessionPreset = AVCaptureSessionPreset1280x720

    let backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)

    let error : NSError?

    var input = AVCaptureDeviceInput()

    do {
        input = try AVCaptureDeviceInput(device: backCamera)
    }
    catch {
        //  error
    }

    if error == nil && (captureSession?.canAddInput(input))! {

        captureSession?.addInput(input)

        stillImageOutput = AVCaptureStillImageOutput()

        stillImageOutput?.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]


        if (captureSession?.canAddOutput(stillImageOutput))! {

            captureSession?.addOutput(stillImageOutput)

            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

            previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill

            previewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait

            cameraView.layer.addSublayer(previewLayer!)

            captureSession?.startRunning() 

        }
    }

}

}

I can't run the application because of this line:

var input = AVCaptureDeviceInput()
3 Answers

In Swift 4, you have to specify a device in order to initialize AVCaptureDeviceInput - in fact, you are already initializing it with one two lines after the code that throws the error.

Moreover, you are implicitly unwrapping an otherwise safely unwrapped AVCaptureSession in the if statement right after that.

Here is your code, polished:

do {
    guard let input = try AVCaptureDeviceInput(device: backCamera),
        captureSession = captureSession else {
        print("Error in initializing a device input")
    }

    if error == nil && (captureSession.canAddInput(input)) {

    [...]
}
catch let error {
    print(error.localizedDescription)
}

so I used all of the left codes inside do catch and I got the result and the app is working well in the swift 4 - so instead of view will appear in my question codes use this codes below

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


    captureSession = AVCaptureSession()

    captureSession?.sessionPreset = AVCaptureSessionPreset1280x720


    do {
        let input = try AVCaptureDeviceInput(device: .defaultDevice(withMediaType: AVMediaTypeVideo))

        captureSession?.addInput(input)

        stillImageOutput = AVCaptureStillImageOutput()

        stillImageOutput?.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]


        if (captureSession?.canAddOutput(stillImageOutput))! {

            captureSession?.addOutput(stillImageOutput)

            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

            previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill

            previewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait

            cameraView.layer.addSublayer(previewLayer!)

            captureSession?.startRunning()

        }



    } catch {

        print(error)

    }

}

I have answered my question to help other people

You have to use like below:

if let backCamera = AVCaptureDevice.default(for: .video) {
    do {
        var input = try AVCaptureDeviceInput(device: backCamera)
    } catch {
        //  error
    }
}

How to use in your code :

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

    captureSession = AVCaptureSession()
    captureSession?.sessionPreset = AVCaptureSession.Preset.hd1280x720

    guard let backCamera = AVCaptureDevice.default(for: .video) else {
        print("AVCaptureDevice backCamera is nil")
        return
    }

    let error : NSError?

    do {
        let input = try AVCaptureDeviceInput(device: backCamera)

        if (captureSession?.canAddInput(input))! {
            captureSession?.addInput(input)
            stillImageOutput = AVCaptureStillImageOutput()
            stillImageOutput?.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]

            if (captureSession?.canAddOutput(stillImageOutput!))! {
                captureSession?.addOutput(stillImageOutput!)
                previewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
                previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
                previewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
                cameraView.layer.addSublayer(previewLayer!)
                captureSession?.startRunning()
            }
        }
    }
    catch {
        //  error
    }
}
Related