AVCaptureSession 运行时崩溃。致命错误:在展开可选值 (lldb) 时意外发现 nil

Posted

技术标签:

【中文标题】AVCaptureSession 运行时崩溃。致命错误:在展开可选值 (lldb) 时意外发现 nil【英文标题】:AVCaptureSession Runtime crash. fatal error: unexpectedly found nil while unwrapping an Optional value (lldb) 【发布时间】:2015-04-29 05:17:45 【问题描述】:

致命错误:在展开可选值 (lldb) 时意外发现 nil

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

线程1 if deviceInput == nil! 处的致命错误绿色突出显示行。和 beginSession() 呼叫处的另一个错误绿色突出显示行。

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

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

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




【问题讨论】:

【参考方案1】:

看看你的代码,你真的应该尝试摆脱使用!强制解包选项的习惯,尤其是“让它编译”。一般来说,如果你发现自己在写@ 987654327@,可能有更好的方法来编写您想要的内容。尝试查看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。强制转换结果可能不是正确的做法。作为 state 的文档,

如果设备因为不再可用或正在使用而无法打开,例如,此方法返回nil,可选的 outError 参数指向描述问题的NSError

处理这个问题的正确方法是检查结果是nil,并采取适当的行动。所以你想做这样的事情:

if let deviceInput = AVCaptureDeviceInput.deviceInputWithDevice(captureDevice, error: &err) as? AVCaptureInput
    // use deviceInput

else 
    println("error: \(err?.localizedDescription)")

【讨论】:

谢谢。我写了if let deviceInput = AVCaptureDeviceInput.deviceInputWithDevice(captureDevice, error: &err) as? AVCaptureInput // Set the input device captureSession.addInput(deviceInput) else println("error: \(err?.localizedDescription)") ,它摆脱了那个错误,但现在我有这个运行时错误。 i.imgur.com/X7RMcEx.png 和 i.imgur.com/as3MIRx.png。我查看是否同时有 2 个输入或 2 个输出,但看不到问题所在。我应该写一个新问题吗? 是的,一旦您解决了 nil-unwrap 问题,请尝试发布一个新问题。尝试使代码尽可能短以演示问题,这将更有可能让人们回答。 感谢 Airspeed。如果你有机会,请看看我的新问题。 ***.com/questions/29951445/…

以上是关于AVCaptureSession 运行时崩溃。致命错误:在展开可选值 (lldb) 时意外发现 nil的主要内容,如果未能解决你的问题,请参考以下文章

如何正确释放 AVCaptureSession

AVCaptureSession addInput:不适用于 iOS7

将系统ram升级到16 GB面临错误:Java运行时环境检测到致命错误:

应用程序突然崩溃 - 致命的执行引擎错误 (7A0BC59E) (80131506)

AVFoundation -AVCaptureSession 仅在进入后台并返回断点时停止并开始运行

货币转换器Android应用程序中的运行时致命错误