来自另一种语言,我对一个无声的错误感到惊讶,该错误中从未调用过作为回调传递给方法的对象。对回调的引用以某种方式丢失了。
问题的最小(不可运行)示例:
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 calls delegate on screen recording
大多数委托是weak
,因此它们不会创建保留周期,请参阅Automatic Reference Counting (ARC)。大多数情况是假设您正在使用的代理存储为weak
。
在您的第一个示例中,对对象的唯一强引用由函数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
来防止保留周期。