swift - 尽管被进一步传递,但在函数中创建的对象会消失
问题描述
来自另一种语言的我对一个无声的错误感到惊讶,其中一个作为回调突然传递给方法的对象永远不会被调用。对回调的引用不知何故丢失了。
问题的最小(不可运行)示例:
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
解决方案
大多数委托是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()
故意调用的,这样如果你想要一个委托,就会调用这个函数,如果你不想有委托,它不会引起问题。
推荐阅读
- youtube-api - 为什么即使我们使用在上一个 API 结果上写的 `nextPageToken` ,收集视频 ID 的请求也会失败?
- c - 在openpty之后ncurses newterm
- c++ - 向量元素的初始化顺序是否有标准保证?
- python - Pythonnet 支持 .NET Core 还是 .NET 5.0
- security - 是否可以在 MonetDB 中实现行级安全性?
- html - 从左到右到从右到左转换 - 输入
- java - 更改/切换数组中的元素是否可以删除java中的元素(不是关于创建新对象或使用arraylist)?
- kentico - CSS 菜单列表结构
- batch-file - 创建一个 .bat 文件以打开/单击网页上的应用程序/链接?
- python - 在 Pycharm 中安装 PyTorch 时出现此错误。我成功安装了 torchvision 和 torch 但问题出在 PyTorch