如何在不冻结APP的情况下保存同一AVCaptureSession快速拍摄的图片?
问题分析与解决方案
核心原因
直接通过UIImage(ciImage: ciImage)创建的图片对象并未独立存储像素数据,它只是对AVCaptureSession提供的CVImageBuffer的包装。当你把这类UIImage存入数组时,会阻止底层buffer被系统回收,相机的buffer池被耗尽后就会出现冻结现象。后台切换回来时系统会回收部分闲置资源,所以能短暂恢复,但很快又会耗尽。而压缩图片时会将像素数据转为独立的JPEG/PNG数据,脱离了原buffer的依赖,因此不会触发这个问题。
修复步骤
1. 生成带独立像素数据的UIImage
捕获图片时,不要直接用UIImage(ciImage:),而是通过CIContext将CIImage渲染为CGImage,再创建UIImage,这样会生成独立的像素数据,不会占用相机的buffer:
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard takePicture, let buffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } let ciImage = CIImage(cvImageBuffer: buffer) // 用CIContext渲染出独立的CGImage guard let cgImage = ciContext.createCGImage(ciImage, from: ciImage.extent) else { takePicture = false return } let uiImage = UIImage(cgImage: cgImage) DispatchQueue.main.async { self.takePicture = false self.capturedImages.append(uiImage) self.capturedImageImageView.image = uiImage self.imageCountLabel.text = String(self.capturedImages.count) } }
2. 修复线程安全问题
原代码在主队列中嵌套全局队列操作capturedImages,会导致数组读写在不同线程,存在线程安全隐患。统一在主队列操作数组即可:
// 移除原代码中嵌套的全局队列,直接在主队列操作数组 DispatchQueue.main.async { self.takePicture = false self.capturedImages.append(uiImage) self.capturedImageImageView.image = uiImage self.imageCountLabel.text = String(self.capturedImages.count) }
3. 复用CIContext提升性能
CIContext创建耗时,建议将其作为类属性初始化,避免每次捕获都重复创建:
class CameraViewController: UIViewController { // 添加CIContext属性 private let ciContext = CIContext(options: [.useSoftwareRenderer: false]) // ... 其他属性 // 后续捕获方法中直接复用ciContext }
4. 补充相机权限检查
原代码checkPermissions()为空,相机权限是功能正常运行的前提,补充权限检查:
private func checkPermissions() { switch AVCaptureDevice.authorizationStatus(for: .video) { case .authorized: break case .notDetermined: AVCaptureDevice.requestAccess(for: .video) { granted in if granted { DispatchQueue.main.async { self.setUpAndStartCaptureSession() } } else { // 提示用户开启相机权限 } } case .denied, .restricted: // 引导用户前往设置开启权限 break @unknown default: break } }
内容的提问来源于stack exchange,提问作者KevinF
相关产品推荐
相关产品推荐

