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

在类A中使用类B定义的AVCapturePhotoCaptureDelegate未被调用问题

问题:AVCapturePhotoCaptureDelegate协议方法无法触发

我现在有一个遵循AVCapturePhotoCaptureDelegate协议的类B,代理在B的初始化阶段完成设置,但在类A中使用这个代理时,协议方法始终无法被调用。示例代码如下:

class A {
    private var photoOutput = AVCapturePhotoOutput()
    
    @objc func captureFrame() {
        ...
        let b = B(a: self)
        photoOutput.capturePhoto(with: photoSettings, delegate: b)
    }

    func somemethod() {
        ...
    }

}

class B: AVCapturePhotoCaptureDelegate {
    weak var a: A?
    weak var delegate: AVCapturePhotoCaptureDelegate?

    init(a: A) {
        self.a = a
        super.init()
        self.delegate = self
    }
    
    // 这个方法始终不会被调用...
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        print("Delegate method called")
        a?.somemethod()
    }
}

我这么做是因为captureFrame方法可能会被循环调用,需要持久化传入的参数以避免竞态条件。我可能误解了这种实现方式的工作原理,此外我还尝试直接传入代理变量,例如:

photoOutput.capturePhoto(with: photoSettings, delegate: b.delegate)

但问题依然存在。


原因与解决办法

核心问题:代理对象被提前释放

在captureFrame方法中,你创建的B实例是局部变量,方法执行完毕后就会被ARC自动释放。而AVCapturePhotoOutput的capturePhoto(with:delegate:)方法对代理对象的引用是弱引用,不会持有它,所以当方法执行完,B实例已经被销毁,自然无法触发协议方法。

另外,你在B类中额外声明的weak var delegate: AVCapturePhotoCaptureDelegate?完全是多余的——B本身已经遵循了协议,直接用B实例作为代理即可,不需要多此一举。

修复步骤

  1. 在类A中添加成员变量持有B实例,避免它被提前释放:
class A {
    private var photoOutput = AVCapturePhotoOutput()
    // 添加变量持有B实例,防止被提前释放
    private var photoDelegate: B?
    
    @objc func captureFrame() {
        ...
        let b = B(a: self)
        photoDelegate = b
        photoOutput.capturePhoto(with: photoSettings, delegate: b)
    }

    func somemethod() {
        ...
    }
}
  1. 简化B类,移除多余的delegate属性:
class B: AVCapturePhotoCaptureDelegate {
    weak var a: A?

    init(a: A) {
        self.a = a
        super.init()
    }
    
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        print("Delegate method called")
        a?.somemethod()
        // 回调完成后可手动置空代理实例,避免不必要的内存占用
        (a as? A)?.photoDelegate = nil
    }
}

补充说明

如果captureFrame会被频繁调用,每次调用都需要创建新的B实例,那么在协议方法回调完成后,记得手动将photoDelegate置空,避免内存浪费。同时,由于a是弱引用,不会产生循环引用问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 16:23:10