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

Swift自定义相机报错:No active and enabled video connection 求助

Fixing 'No active and enabled video connection' Error in Swift Custom Camera App

Hey there! Let's work through why you're hitting this frustrating error when trying to take a photo. I've looked over your code and spotted a few key issues that are causing this problem—let's break them down and fix them step by step.

Key Issues in Your Code

Let's start with what's going wrong:

1. Duplicate stillImageOutput Initialization

In your viewDidAppear method, you create a stillImageOutput, add it to the capture session, but then reinitialize it again at the end of the method. This replaces the output that was actually connected to your session with a brand new, unlinked instance. When you call capturePhoto(with:delegate:), this new output has no active connection to the session—hence the error.

2. No Validation for Active Video Connections

You're not checking if the stillImageOutput has a valid, active video connection before attempting to capture a photo. Even if other setup steps are correct, this can lead to crashes if the camera isn't fully ready.

3. Repeated Capture Session Initialization

You create a new AVCaptureSession every time the view appears. This is unnecessary and can cause conflicts with existing camera connections.

4. Missing Explicit Protocol Conformance

While you have the photoOutput delegate method, your view controller doesn't explicitly state it conforms to AVCapturePhotoCaptureDelegate—this can cause the delegate system to fail silently, breaking the photo capture flow.


Step-by-Step Fixes

Let's fix each issue one by one:

1. Remove the Duplicate stillImageOutput Initialization

In your viewDidAppear method, delete this final line that reinitializes the output:

stillImageOutput = AVCapturePhotoOutput()

2. Add Connection Validation Before Capturing

Update your takePhotoBtnPressed method to check for a valid active connection first—this adds a safety net to prevent crashes:

@IBAction func takePhotoBtnPressed(_ sender: Any) {
    // Check if we have an active video connection
    guard let connection = stillImageOutput?.connection(with: .video), connection.isActive else {
        print("No active video connection available")
        return
    }
    
    let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
    stillImageOutput!.capturePhoto(with: settings, delegate: self)
}

3. Reuse the Capture Session (Don't Recreate It)

Declare your session, output, and preview layer as class-level properties (not inside methods) so you can reuse them instead of creating new instances every time the view appears:

class YourViewController: UIViewController {
    @IBOutlet weak var imageView: UIView! 
    @IBOutlet weak var outputImageView: UIImageView!
    
    // Class-level properties to persist camera resources
    private var session: AVCaptureSession?
    private var stillImageOutput: AVCapturePhotoOutput?
    private var videoPreviewLayer: AVCaptureVideoPreviewLayer?
    
    // Rest of your code...
}

Then update viewDidAppear to only initialize the session if it doesn't exist yet:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    
    // Start the session if it already exists, otherwise set up the camera
    if let session = session {
        if !session.isRunning {
            session.startRunning()
        }
    } else {
        setupCamera()
    }
}

4. Explicitly Conform to AVCapturePhotoCaptureDelegate

Update your view controller class declaration to include the protocol—this ensures the system recognizes your delegate methods:

class YourViewController: UIViewController, AVCapturePhotoCaptureDelegate {
    // Your code here...
}

Full Modified Code Example

Here's the complete corrected code with all fixes applied (I've also added a helper method for camera setup to keep things organized):

import UIKit
import AVFoundation

class CameraViewController: UIViewController, AVCapturePhotoCaptureDelegate {
    
    @IBOutlet weak var imageView: UIView! 
    @IBOutlet weak var outputImageView: UIImageView!
    
    private var session: AVCaptureSession?
    private var stillImageOutput: AVCapturePhotoOutput?
    private var videoPreviewLayer: AVCaptureVideoPreviewLayer?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Handle camera authorization
        if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
            print("Camera authorized")
        } else {
            AVCaptureDevice.requestAccess(for: .video) { granted in
                if granted {
                    DispatchQueue.main.async {
                        // Re-setup camera if permission is granted after initial load
                        self.setupCamera()
                    }
                } else {
                    print("Camera permission denied")
                }
            }
        }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // Start session if it exists, otherwise setup camera
        if let session = session {
            if !session.isRunning {
                session.startRunning()
            }
        } else {
            setupCamera()
        }
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        session?.stopRunning()
    }
    
    // Helper method to centralize camera setup
    private func setupCamera() {
        session = AVCaptureSession()
        session?.sessionPreset = .low
        
        guard let backCamera = AVCaptureDevice.default(for: .video) else {
            print("Unable to access back camera!")
            return
        }
        
        do {
            let input = try AVCaptureDeviceInput(device: backCamera)
            stillImageOutput = AVCapturePhotoOutput()
            
            if let session = session, session.canAddInput(input), session.canAddOutput(stillImageOutput!) {
                session.addInput(input)
                session.addOutput(stillImageOutput!)
                setupLivePreview()
            }
        } catch let error {
            print("Error Unable to initialize back camera: \(error.localizedDescription)")
        }
    }

    @IBAction func takePhotoBtnPressed(_ sender: Any) {
        guard let connection = stillImageOutput?.connection(with: .video), connection.isActive else {
            print("No active video connection available")
            return
        }
        
        let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
        stillImageOutput!.capturePhoto(with: settings, delegate: self)
    } 

    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { 
        if let error = error {
            print("Photo capture error: \(error.localizedDescription)")
            return
        }
        
        guard let imageData = photo.fileDataRepresentation() else { 
            print("Failed to get photo data")
            return 
        } 
        let image = UIImage(data: imageData) 
        outputImageView.image = image 
    } 

    func setupLivePreview() { 
        guard let session = session else { return }
        
        videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session)
        videoPreviewLayer?.videoGravity = .resizeAspectFill
        videoPreviewLayer?.connection?.videoOrientation = .portrait
        imageView.layer.addSublayer(videoPreviewLayer!)
        
        DispatchQueue.global(qos: .userInitiated).async { 
            session.startRunning() 
            DispatchQueue.main.async { 
                self.videoPreviewLayer?.frame = self.imageView.bounds 
            } 
        } 
    } 
}

Why These Fixes Work

  • Removing duplicate initialization ensures you're using the stillImageOutput instance that's actually connected to the capture session.
  • Connection validation adds a safety check to prevent crashes when the camera isn't fully ready.
  • Reusing the session avoids conflicts from creating multiple sessions and ensures consistent camera connections.
  • Explicit protocol conformance guarantees the delegate methods are recognized and called correctly by the system.

内容的提问来源于stack exchange,提问作者jonye._.jin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:03:32