苹果AVCam示例代码为何未用layerWithSession?预览层会话关联疑问
关于AVCam示例中捕获会话与预览层关联的说明及主线程卡顿解决
首先,你没看错——AVCam示例里确实没有直接调用layerWithSession:来创建AVCaptureVideoPreviewLayer,核心原因是**AVCamPreviewView是一个自定义的UIView,它的底层layer本身就是AVCaptureVideoPreviewLayer**,而不是普通的CALayer。
1. AVCamPreviewView的底层逻辑
AVCamPreviewView重写了类方法+layerClass,直接返回AVCaptureVideoPreviewLayer.class:
+ (Class)layerClass { return [AVCaptureVideoPreviewLayer class]; }
这意味着,当你创建AVCamPreviewView实例时,它的layer属性已经是一个AVCaptureVideoPreviewLayer对象了。示例里给AVCamPreviewView的session属性赋值,本质上是把会话传递给了内部的预览层:
// AVCamPreviewView的session属性实现大概是这样的 - (void)setSession:(AVCaptureSession *)session { [(AVCaptureVideoPreviewLayer *)self.layer setSession:session]; }
这就完成了捕获会话和预览层的关联,不需要显式调用layerWithSession:。
2. 为什么你用layerWithSession:会导致主线程卡顿
layerWithSession:方法在初始化AVCaptureVideoPreviewLayer时,会同步完成一些和硬件设备绑定、视频格式协商的操作,这些操作本身是比较耗时的。如果在主线程执行,就会阻塞UI线程,导致你看到的10秒卡顿。
而AVCam示例的做法是先创建预览层(通过创建AVCamPreviewView自动生成),再设置session,这个过程把初始化和会话绑定拆成了两步,避免了在主线程一次性执行所有耗时操作。
3. 解决主线程卡顿的建议
- 复用AVCam的自定义View方案:自己实现一个类似
AVCamPreviewView的自定义UIView,重写+layerClass返回AVCaptureVideoPreviewLayer,然后通过View的属性来设置session,这样可以避开layerWithSession:的同步耗时初始化。 - 后台初始化预览层:如果一定要用
layerWithSession:,把初始化操作放到后台线程执行,初始化完成后再回到主线程将layer添加到View上:dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession]; // 配置预览层的frame、视频重力等属性 dispatch_async(dispatch_get_main_queue(), ^{ [self.previewContainerView.layer addSublayer:previewLayer]; }); }); - 优化捕获会话配置:检查你对
AVCaptureSession的配置(比如设置预设、添加输入输出)是否也在主线程执行,这些操作同样可能耗时,建议放到后台线程完成后,再启动会话并关联预览层。
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

