NSViewController 如何避免绑定内存泄漏? [有示例应用程序]

Posted

技术标签:

【中文标题】NSViewController 如何避免绑定内存泄漏? [有示例应用程序]【英文标题】:How does NSViewController avoid bindings memory leak? [have sample app] 【发布时间】:2010-01-17 13:46:13 【问题描述】:

我正在尝试实现我自己的 NSViewController 版本(为了向后兼容),但我遇到了绑定问题:由于绑定保留了它们的目标,所以每当我通过 File 的所有者绑定时,我都有一个保留圈。

所以我想我只是从其父视图中显式删除我的视图并释放***对象,这将处理绑定,因为我的控制器不再保留视图,所以它们释放了我我可以走了。但是由于某种原因,我的视图控制器仍然没有被释放。这是一个展示该问题的示例应用程序:

http://dl.dropbox.com/u/34351/BindingsLeak.zip

构建它,启动它,然后点击 Cmd-K(“编辑”菜单中的“创建 Nib”)将一个 NIB 加载到空窗口中。再次按下 Cmd-K 以释放第一个视图控制器 (TestNibOwner) 并加载一个新的。不过,旧的视图控制器永远不会被释放。

删除复选框上的“值”绑定,它就可以正常释放了。

如果您在 release/retain/autorelease 覆盖处设置断点,您会看到 _NSBindingInfo 保留了 TestNibOwner,但在泄漏的情况下从不释放它。

有人知道如何解决这个问题吗?

【问题讨论】:

对不起,我不想先下载项目来帮助你。你能提供一些代码吗? 【参考方案1】:

与 class-dump 和朋友一起做一些调查,看起来 Apple 有一个名为 NSAutounbinder 的私有类,它负责为 NSViewController 和 NSWindowController 等类处理这项肮脏的工作。无法真正说出它是如何工作的或如何复制它。

所以,我无法真正回答您关于如何防止在加载的 nib 中的任意绑定发生保留周期的问题,但知道 Apple 正在作弊可能是一种安慰,而且您没有遗漏任何明显的东西. :-)

【讨论】:

【参考方案2】:

我为同样的问题做的一件事是在我的笔尖内创建一个代理 NSObjectController。我的类似 NSViewController 的类有一个指向该代理的指针,所有绑定都通过它绑定。当我想清理视图控制器时,我在对象控制器上执行 [selfProxy setContent:nil] 并释放视图控制器。在这种情况下,NSObjectController 代理在这种情况下充当自动取消绑定器。

它更手动,你不能只释放视图本身,但它确实解决了保留问题。

我建议你这样做:

-(void) releaseTopLevelObjects

    // Unbind the object controller's content by setting it to nil.
    [selfProxy setContent:nil];

    NSLog( @"topLevelObjects = %@", topLevelObjects );
    [topLevelObjects release];
    topLevelObjects = nil;

在您的笔尖中,绑定将通过如下路径发生:

selfProxy.content.representedObject.fooValue

【讨论】:

谢谢!我已经在网络上看到了许多骇人听闻的修复尝试,但这是我实际上敢于发布的解决方法。可惜没有真正的方法来进行自动解除绑定。【参考方案3】:

当您从其超级视图中删除您的视图时,您是否还向它发送了另一个 -release 消息?它是通过从 ni​​b 取消归档创建的,对吧?

【讨论】:

是的,releaseTopLevelObjects 释放视图(以及可能存在的任何其他未归档对象)。至少这是它应该做的。

以上是关于NSViewController 如何避免绑定内存泄漏? [有示例应用程序]的主要内容,如果未能解决你的问题,请参考以下文章

绑定到NSViewController的representObject

在基于文档的 Cocoa 应用程序中避免耦合?

如何从 NSViewController 显示视图?

如何在 Mac OS X 应用程序中从一个 NSViewcontroller 推送到另一个 NSViewcontroller?

如何避免内存溢出和频繁的垃圾回收

如何避免内存溢出和频繁的垃圾回收