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

Swift开发iOS相机应用前后置相机切换异常问题求助

修复iOS相机前后置切换失效的问题

嘿,我仔细看了你的代码,发现几个关键问题导致切换相机功能失效,咱们一步步来修复:

核心问题分析

  • 重复创建CaptureSession且未清理旧资源:你每次切换相机时都重新初始化了captureSession,还直接把新的videoPreviewLayer叠加到ImageView上,这会导致旧的会话和图层残留,新会话无法正常接管相机资源。
  • 相机设备获取兼容性差:使用.builtInDualCamera只能获取双摄像头设备的相机,单摄设备(比如iPhone SE 第一代)会返回nil,应该用.builtInWideAngleCamera来兼容所有带摄像头的iOS设备。
  • Session配置顺序错误:在viewDidLoad中,你先启动了session,之后才添加AVCapturePhotoOutput和设置sessionPreset,这些配置需要在session启动前完成才能生效。

修复后的完整代码

import UIKit
import AVFoundation

class ViewController: UIViewController {
    @IBOutlet weak var imageView: UIView! // 变量名改用小驼峰,符合Swift规范
    var captureSession: AVCaptureSession?
    var videoPreviewLayer: AVCaptureVideoPreviewLayer?
    var capturePhotoOutput: AVCapturePhotoOutput?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupCamera(with: .back) // 初始化时直接调用通用设置函数
    }
    
    // 通用相机设置函数,传入要切换的相机位置
    private func setupCamera(with position: AVCaptureDevice.Position) {
        // 停止当前会话(如果存在)
        captureSession?.stopRunning()
        
        // 1. 获取指定位置的相机设备
        guard let captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: position) else {
            print("无法获取指定位置的相机")
            return
        }
        
        // 2. 配置Session
        let session = AVCaptureSession()
        session.sessionPreset = .photo // 先设置预设
        
        do {
            // 添加视频输入
            let input = try AVCaptureDeviceInput(device: captureDevice)
            if session.canAddInput(input) {
                session.addInput(input)
            }
            
            // 添加拍照输出
            let photoOutput = AVCapturePhotoOutput()
            photoOutput.isHighResolutionCaptureEnabled = true
            photoOutput.isDepthDataDeliveryEnabled = photoOutput.isDepthDataDeliverySupported
            photoOutput.isPortraitEffectsMatteDeliveryEnabled = photoOutput.isPortraitEffectsMatteDeliverySupported
            
            if session.canAddOutput(photoOutput) {
                session.addOutput(photoOutput)
                capturePhotoOutput = photoOutput
            }
            
            // 3. 配置预览层
            let previewLayer = AVCaptureVideoPreviewLayer(session: session)
            previewLayer.frame = imageView.layer.bounds
            previewLayer.videoGravity = .resizeAspectFill // 添加视频填充模式,避免拉伸
            
            // 移除旧的预览层,添加新的
            imageView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
            imageView.layer.addSublayer(previewLayer)
            
            // 保存会话和预览层的引用
            captureSession = session
            videoPreviewLayer = previewLayer
            
            // 4. 启动会话
            session.startRunning()
        } catch {
            print("相机配置错误: \(error.localizedDescription)")
        }
    }
    
    @IBAction func rotateCamera(_ sender: Any) {
        guard let currentInput = captureSession?.inputs.first as? AVCaptureDeviceInput else {
            print("无法获取当前相机输入")
            return
        }
        
        // 根据当前相机位置切换到相反的相机
        let targetPosition: AVCaptureDevice.Position = currentInput.device.position == .back ? .front : .back
        setupCamera(with: targetPosition)
    }
}

关键修复点说明

  • 复用+清理资源:每次切换时先停止旧会话,移除旧的预览层,避免资源冲突和图层叠加。
  • 通用相机获取:用.builtInWideAngleCamera替代.builtInDualCamera,兼容更多设备。
  • 统一配置流程:把相机配置逻辑封装到一个函数中,确保预设、输入输出添加都在会话启动前完成。
  • 规范命名:把ImageView改成imageView,符合Swift的命名规范,避免和系统类混淆。

现在你可以测试一下,切换按钮应该能正常在前后置相机之间切换了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:15:59