首页 > 解决方案 > 尽管被进一步传递,但在函数中创建的对象会消失

问题描述

来自另一种语言的我对一个无声的错误感到惊讶,其中一个作为回调突然传递给方法的对象永远不会被调用。对回调的引用不知何故丢失了。

问题的最小(不可运行)示例:

class Foo: NSObject, AVCaptureFileOutputRecordingDelegate {
    func bar() {
        let out = AVCaptureMovieFileOutput()
        let delegate = Foo() //nonsensical in this case, in normal case diff. object will be used
        out.startRecording(to: /*...*/, recordingDelegate: delegate)

        //Result: delegate methods are never called
    }
}

“解决方案”的最小(不可运行)示例:

class Foo: NSObject, AVCaptureFileOutputRecordingDelegate {
    func bar() {
        let out = AVCaptureMovieFileOutput()
        out.startRecording(to: /*...*/, recordingDelegate: self)

        //Result: delegate methods are called when approperiate
    }
}

我很困惑...


这个问题源于AVCaptureMovieFileOutput never call delegate on screen recording

标签: swiftsyntaxgarbage-collection

解决方案


大多数委托是weak为了不创建保留周期,请参阅自动引用计数 (ARC)。其中大部分是假设您正在使用的委托存储是weak.

在您的第一个示例中,对对象的唯一强引用由 function 持有bar,因为委托是弱引用。一旦函数结束,唯一剩下的强引用就消失了,对象就可以被删除了。

class Foo: NSObject, AVCaptureFileOutputRecordingDelegate {
    func bar() {
        let out = AVCaptureMovieFileOutput()
        let delegate = Foo() //object created, and strong reference stored in variable called delegate
        out.startRecording(to: /*...*/, recordingDelegate: delegate) // object passed in and likely stored in a weak variable inside of the `out` object. This means it will not keep a strong reference to your Foo object.

        //Result: delegate methods are never called
    }// local variable called delegate goes out of scope, strong reference to your Foo object goes away, there are no more strong references, can be deleted.
}

在第二个示例中,当self用作委托时,self很可能在函数结束后bar仍然存在,因此委托仍然存在。

class Foo: NSObject, AVCaptureFileOutputRecordingDelegate {
    func bar() {
        let out = AVCaptureMovieFileOutput()
        out.startRecording(to: /*...*/, recordingDelegate: self) // pass `self`, which presumably has something else referencing it with a strong reference, so it stays alive

        //Result: delegate methods are called when approperiate
    } // `self` still has strong references to it (somewhere else) keeping it alive after the function call, so the weak reference that is being used to call the delegate methods can still operate! Yay!
}

希望这能回答“为什么”。

至于预防,您需要确保对您想要保持活力的任何委托(或弱变量)保持强引用。

此行为是设计使然,因为它用于防止保留周期和内存泄漏。在使用委托设计您自己的类时,您可以weak在必要时适当地使用以防止保留循环。

至于失败的静默,在很多情况下,委托是可选的,委托为 nil 和委托函数没有被调用不被认为是失败。很多时候,函数是delegate?.delegateMethod()故意调用的,这样如果你想要一个委托,就会调用这个函数,如果你不想有委托,它不会引起问题。


推荐阅读