Swift悬空引用
Swift悬空引用

Swift悬空引用

悬空引用(Dangling Reference)或悬空指针(Dangling Pointer)是指:

变量仍然指向已经被释放(销毁)的内存地址。

正常引用流程

var window = NSWindow()
let myRef = window    // 正常引用
// window 仍然存在,myRef 是有效的引用

悬空引用示例

weak var myRef: NSWindow? = createWindow()
myRef?.close()
myRef?.title = "Hello" // 崩溃:myRef 指向已销毁内存,访问无效

这类崩溃通常是 EXC_BAD_ACCESS 或 EXC_BREAKPOINT,因为访问了已经被系统释放掉的内存地址。

崩溃的原因在于:试图设置为 nil 时,myRef可能指向的是一块已经被释放、销毁但未清理引用的内存,也就是说:它已经不是一个安全的 NSWindow 对象,这就触发了“悬空引用崩溃”。

问题原因

在 macOS 中,NSWindow 和 NSWindowController 的生命周期管理非常复杂,涉及:

1、run loop 中的窗口事件队列

2、NSWindowDelegate 中的 windowWillClose / windowDidClose 延迟触发

3、NSApplication 对窗口的 retain/release 管理

4、如果使用 weak var,系统在 window 被销毁时自动将其置为 nil,再设置一次会触发不可预知行为。

解决方案

1、使用windowDidClose设置为nil:

func windowDidClose(_ notification: Notification) {
    DispatchQueue.main.async {
        self.myRef = nil
    }
}

2、避免主动置为nil,使用weak var

weak var myRef: NSWindow?

在窗口销毁后,系统自动清空指针。

3、不手动设置为nil,交给ARC

myRef ?.close()
// 不用手动设置为 nil,让 ARC 和 weak 自动管理

总结

因为Swift悬空引用的问题,目前只在使用NSWindow时,发生过。相关案例请见《macOS关于NSWindow被释放后访问Optional崩溃的问题》。

而我的解决方案是,不设置为nil,交给ARC(自动引用计数)处理。

扩展知识

1、macOS关于NSWindow被释放后访问Optional崩溃的问题:https://fangjunyu.com/2025/07/28/macos%e5%85%b3%e4%ba%8enswindow%e8%a2%ab%e9%87%8a%e6%94%be%e5%90%8e%e8%ae%bf%e9%97%aeoptional%e5%b4%a9%e6%ba%83%e7%9a%84%e9%97%ae%e9%a2%98/

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注