ios - AVCaptureSession 运行时崩溃。 fatal error : unexpectedly found nil while unwrapping an Optional value (lldb)

标签 ios swift debugging

fatal error :在展开可选值 (lldb) 时意外发现 nil

此消息是因为我的变量设置为 nil 但代码期望它不是 nil。但我没有解决办法。当我从转换和分配中删除问号时,会发生其他错误。

线程1 if deviceInput == nil! 处的 fatal error 绿色突出显示行。和 beginSession() 调用中的另一个错误绿色突出显示行。

应用程序启动,相机手电筒根据我的代码自动打开,但随后应用程序在那里崩溃。应用程序继续运行,卡在启动屏幕上,手电筒仍亮着。

能否请您查看设置了多少摄像头 session 并告诉我出了什么问题?谢谢

import UIKit
import Foundation
import AVFoundation
import CoreMedia
import CoreVideo

class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {

let captureSession = AVCaptureSession()
var captureDevice : AVCaptureDevice?
var validFrameCounter: Int = 0

// for sampling from the camera
enum CurrentState {
    case statePaused
    case stateSampling
}
var currentState = CurrentState.statePaused

override func viewDidLoad() {
    super.viewDidLoad()

    captureSession.sessionPreset = AVCaptureSessionPresetHigh

    let devices = AVCaptureDevice.devices()

    // Loop through all the capture devices on this phone
    for device in devices {
        // Make sure this particular device supports video
        if (device.hasMediaType(AVMediaTypeVideo)) {
            // Finally check the position and confirm we've got the back camera
            if(device.position == AVCaptureDevicePosition.Back) {
                captureDevice = device as? AVCaptureDevice
                if captureDevice != nil {
                    //println("Capture device found")
                    beginSession() // fatal error
                }
            }
        }
    }

}

// configure device for camera and focus mode


// start capturing frames
func beginSession() {

    // Create the AVCapture Session

    var err : NSError? = nil
    captureSession.addInput(AVCaptureDeviceInput(device: captureDevice, error: &err))

    if err != nil {
        println("error: \(err?.localizedDescription)")
    }

    // Automatic Switch ON torch mode
    if  captureDevice!.hasTorch {
        // lock your device for configuration
        captureDevice!.lockForConfiguration(nil)
        // check if your torchMode is on or off. If on turns it off otherwise turns it on
        captureDevice!.torchMode = captureDevice!.torchActive ? AVCaptureTorchMode.Off : AVCaptureTorchMode.On
        // sets the torch intensity to 100%
        captureDevice!.setTorchModeOnWithLevel(1.0, error: nil)
        // unlock your device
        captureDevice!.unlockForConfiguration()
    }

    // Create a AVCaptureInput with the camera device
    var deviceInput : AVCaptureInput = AVCaptureDeviceInput.deviceInputWithDevice(captureDevice, error: &err) as! AVCaptureInput
    if deviceInput == nil! {   // fatal error: unexpectedly found nil while unwrapping an Optional value (lldb)
        println("error: \(err?.localizedDescription)")
    }

    // Set the output
    var videoOutput : AVCaptureVideoDataOutput = AVCaptureVideoDataOutput()

    // create a queue to run the capture on
    var captureQueue : dispatch_queue_t = dispatch_queue_create("captureQueue", nil)

    // setup ourself up as the capture delegate
    videoOutput.setSampleBufferDelegate(self, queue: captureQueue)

    // configure the pixel format
    videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_32BGRA)]
    // kCVPixelBufferPixelFormatTypeKey is a CFString btw.

    // set the minimum acceptable frame rate to 10 fps
    captureDevice!.activeVideoMinFrameDuration = CMTimeMake(1, 10)

    // and the size of the frames we want - we'll use the smallest frame size available
    captureSession.sessionPreset = AVCaptureSessionPresetLow

    // Add the input and output
    captureSession.addInput(deviceInput)
    captureSession.addOutput(videoOutput)


    // Start the session
    captureSession.startRunning()


    func setState(state: CurrentState){
        switch state
        {
        case .statePaused:
            // what goes here? Something like this?
            UIApplication.sharedApplication().idleTimerDisabled = false
        case .stateSampling:
            // what goes here? Something like this?
            UIApplication.sharedApplication().idleTimerDisabled = true  

        }
    }

    // sampling from the camera
    currentState = CurrentState.stateSampling


    // stop the app from sleeping
    UIApplication.sharedApplication().idleTimerDisabled = true

    // update our UI on a timer every 0.1 seconds
    NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)

    func stopCameraCapture() {
        captureSession.stopRunning()

    }


    // pragma mark Pause and Resume of detection
    func pause() {
        if currentState == CurrentState.statePaused {
            return
        }

        // switch off the torch
        if captureDevice!.isTorchModeSupported(AVCaptureTorchMode.On) {
            captureDevice!.lockForConfiguration(nil)
            captureDevice!.torchMode = AVCaptureTorchMode.Off
            captureDevice!.unlockForConfiguration()
        }
        currentState = CurrentState.statePaused
        // let the application go to sleep if the phone is idle
        UIApplication.sharedApplication().idleTimerDisabled = false
    }


    func resume() {
        if currentState != CurrentState.statePaused {
            return
        }

        // switch on the torch
        if captureDevice!.isTorchModeSupported(AVCaptureTorchMode.On) {
            captureDevice!.lockForConfiguration(nil)
            captureDevice!.torchMode = AVCaptureTorchMode.On
            captureDevice!.unlockForConfiguration()
        }
        currentState = CurrentState.stateSampling
        // stop the app from sleeping
        UIApplication.sharedApplication().idleTimerDisabled = true
}

}
}

最佳答案

看看你的代码,你真的应该尝试摆脱使用 ! 强制解包选项的习惯,尤其是为了“让它编译”。一般来说,如果你曾经发现自己正在编写 if something != nil,可能有更好的方法来编写您想要的内容。尝试查看 this answer 中的示例以复制一些习语。您可能还会发现 this answer对于为什么可选值有用的高级解释很有用。

AVCaptureDeviceInput.deviceInputWithDevice 返回一个 AnyObject,并且您使用此行将其强制转换为 AVCaptureInput:

var deviceInput = AVCaptureDeviceInput.deviceInputWithDevice(captureDevice, error: &err) as! AVCaptureInput

(你不需要声明deviceInput的类型,Swift可以从右边的值推导出来)

当您编写 as! 时,您是在告诉编译器“不要跟我争论,强制结果为 AVCaptureInput 类型,不问任何问题”。如果事实证明返回的是不同类型的东西,您的应用程序将因错误而崩溃。

但是在下一行,你写:

if deviceInput == nil! {

我真的很惊讶这个编译!但事实证明确实如此,它崩溃也就不足为奇了。强制展开一个 nil 的值会崩溃,而你正在以最纯粹的形式执行此操作,强制展开一个 nil 文字 :)

问题是,您已经声明 deviceInput 是非可选类型 AVCaptureInput。强制转换结果可能不是正确的做法。作为状态文档,

If the device cannot be opened because it is no longer available or because it is in use, for example, this method returns nil, and the optional outError parameter points to an NSError describing the problem.

处理此问题的正确方法是检查结果是否为 nil,然后采取适当的措施。所以你想做这样的事情:

if let deviceInput = AVCaptureDeviceInput.deviceInputWithDevice(captureDevice, error: &err) as? AVCaptureInput
    // use deviceInput
}
else {
    println("error: \(err?.localizedDescription)")
}

关于ios - AVCaptureSession 运行时崩溃。 fatal error : unexpectedly found nil while unwrapping an Optional value (lldb),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29934931/

相关文章:

ios - 如何在 Carthage 框架中使用框架?

ios - Swift:将标签与另一个控件放在一起

ios - 如何调试 iOS 应用程序扩展?

debugging - Safari 开发者工具 : Preserve Network Log on Navigation

linux - 我怎样才能找到程序停止的原因?

ios - Titanium ios 联系电话自定义标签?

ios - 如何在 xib 本地化之间切换

ios - Today Extension 有标题,但没有正文 iOS 8

ios - 失败 : permission_denied when setValue: or removeValue: in Firebase Database | Swift 4

c++ - 调试器如何设法中断任何抛出?