You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift打开前置摄像头时偶现nil解包错误的解决方案

解决前置摄像头解包崩溃及被占用问题

问题拆解

你在Crashlytics日志里看到的Unexpectedly found nil while unwrapping an Optional value崩溃,根源是frontCamera在某些场景下为nil——比如设备无前置摄像头、权限未授予、摄像头被其他应用占用导致获取失败,原代码里的强制解包frontCamera!直接触发了崩溃。你改成可选绑定后虽然避免了崩溃,但遇到摄像头被占用的情况时无法正常打开,需要针对性处理这类场景。

优化后的解决方案

下面是兼顾安全解包、可靠获取摄像头和处理占用场景的完整代码:

func startCamera() {
    captureSession = AVCaptureSession()
    captureSession.sessionPreset = .high
    
    // 直接定位前置摄像头,比遍历更高效准确
    guard let frontCamera = AVCaptureDevice.DiscoverySession(
        deviceTypes: [.builtInWideAngleCamera],
        mediaType: .video,
        position: .front
    ).devices.first else {
        print("当前设备无前置摄像头")
        showCameraAlert(message: "当前设备没有前置摄像头,无法使用该功能")
        return
    }
    
    do {
        // 尝试创建摄像头输入对象
        let input = try AVCaptureDeviceInput(device: frontCamera)
        stillImageOutput = AVCapturePhotoOutput()
        
        // 检查会话是否能添加输入输出
        guard captureSession.canAddInput(input), let output = stillImageOutput, captureSession.canAddOutput(output) else {
            print("无法将输入/输出添加到捕获会话")
            showCameraAlert(message: "摄像头初始化失败,请稍后重试")
            return
        }
        
        captureSession.addInput(input)
        captureSession.addOutput(output)
        setupLivePreview()
        
    } catch let error as NSError {
        // 区分不同错误类型,给出对应提示
        switch error.code {
        case AVError.deviceIsExclusiveUseByAnotherProcess.rawValue:
            print("摄像头被其他应用占用")
            showCameraAlert(message: "摄像头正在被其他应用使用,请关闭相关应用后重试")
        case AVError.notAuthorized.rawValue:
            print("摄像头权限未授予")
            showCameraAlert(message: "请前往设置开启摄像头权限后再尝试")
        default:
            print("摄像头初始化错误: \(error.localizedDescription)")
            showCameraAlert(message: "摄像头打开失败:\(error.localizedDescription)")
        }
    }
}

// 辅助方法:弹出摄像头相关提示弹窗
func showCameraAlert(message: String) {
    let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "确定", style: .default))
    
    // 确保在主线程弹窗
    DispatchQueue.main.async {
        if let rootVC = UIApplication.shared.keyWindow?.rootViewController {
            rootVC.present(alert, animated: true)
        }
    }
}

核心优化点

  1. 精准获取前置摄像头:直接通过DiscoverySession指定position: .front获取设备,避免遍历可能出现的遗漏,同时快速判断设备是否支持前置摄像头。
  2. 彻底消除解包崩溃:全程使用guard let进行可选绑定,杜绝任何强制解包操作,从根源上解决nil解包崩溃。
  3. 针对性错误处理:捕获AVError的具体错误码,区分摄像头被占用、权限不足、设备不支持等场景,给用户明确的操作指引,而不是模糊的错误信息。
  4. 用户友好提示:通过弹窗告知用户具体问题,引导用户解决(比如关闭占用摄像头的应用、开启权限),提升体验。

额外建议

  • 在调用startCamera之前,先检查摄像头权限状态,如果未授权,提前引导用户前往设置开启,减少后续错误场景。
  • 如果业务需要,可以在提示弹窗中添加“重试”按钮,让用户可以在解决问题后快速重试打开摄像头。

内容的提问来源于stack exchange,提问作者little_android

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 05:42:10