关闭NSDocument窗口时启用EXC_BAD_ACCESS(启用ARC)

时间:2017-05-14 21:14:06

标签: objective-c macos exc-bad-access nsdocument nszombie

我正致力于将基于文档的应用程序从垃圾收集(在10.6下运行正常)转换为自动引用计数(试图让它编译并运行10.12)。我在最后一个窗口关闭时得到一致的EXC_BAD_ACCESS。静态分析器没有标记任何内容。

我使用Instruments查找Zombies,实际上似乎有一条release消息被发送到解除分配的对象。这是跟踪:

#   Event   ∆ RefCt Timestamp       Responsible Library/Responsible Caller
173 Release -1  3   00:05.226.677   Foundation  __48-[NSFileAccessArbiterProxy removeFilePresenter:]_block_invoke
174 Release -1  2   00:05.226.679   Foundation  -[NSFilePresenterXPCMessenger invalidate]
175 Retain  +1  3   00:05.226.823   Foundation  -[NSBlockOperation initWithBlock:]
176 Retain  +1  4   00:05.226.858   AppKit  -[NSDocument close]
177 Release -1  3   00:05.227.350   Foundation  -[NSFilePresenterXPCMessenger dealloc]
Retain/Release (2)  00:05.227.484   AppKit  -[NSDocumentController removeDocument:]
180 Release -1  2   00:05.227.485   AppKit  -[NSDocumentController removeDocument:]
Retain/Release (2)  00:05.227.496   AppKit  -[NSUIActivityManager addProvider:toUserActivity:withSetter:]
183 Autorelease     00:05.227.499   AppKit  -[NSWindowController _windowDidClose]
184 Release -1  1   00:05.228.172   Foundation  -[NSAutoreleasePool drain]
185 Release -1  0   00:05.228.184   Foundation  -[NSBlockOperation dealloc]
186 Zombie      -1  00:05.242.579   AppKit  -[NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed:saveWindows:]

我在诊断这个问题时遇到的困难是,我可以看到消息被发送到僵尸,但因为我没有释放任何对象(这一切都是由ARC完成的),我猜测有在某个地方发生的隐式释放。但我不确定在哪里看。

在调试器中,lldbmain.m处抱怨崩溃:

return NSApplicationMain(argc, (const char **) argv);

非常感谢任何帮助。谢谢。

经过更多研究后,问题仍然没有解决,但我有一个线索:

感谢您的回复。是的,我在这一点上假设它是一个内存管理问题。有没有办法追查罪魁祸首?看起来像使用Zombies in Instruments正在帮助它:它指出了一个问题,但并没有帮助我解决问题。也就是说,根据Instruments的违规行似乎是" - [NSApplication(NSWindowCache)_checkForTerminateAfterLastWindowClosed:saveWindows:]&#34 ;;但我从来没有发过那条线。我已经做了一些可能会有点进展的事情。

我在文档中使用的结构是:

NSDocumentController:默认,不是子类 NSDocument:子类,MyDocument;也是窗口的代表 NSWindowController:默认,不是子类 NSWindowMyDocument.xibMainMenu.xib

我尝试将打开窗口的委托设置为nil,如下所示:

-(void)windowWillClose:(NSNotification *)notification
{
    windowOpen = YES;
    NSArray *windowControllers = [self windowControllers];
    NSWindowController *currentWindowController = [windowControllers firstObject];
    NSWindow *windowForCurrentController = [currentWindowController window];
    NSDocument *w = [windowForCurrentController delegate];
    [windowForCurrentController setDelegate:nil];
}

这导致同样的崩溃。

然后,我想也许currentWindowController(或应用程序)正在发送一个解除分配的窗口。所以我尝试添加该行(在上述方法的最后):

[currentWindowController setWindow:nil];

这消除了崩溃,但引入了新问题(例如在尝试加载新文件时等)。但我想知道这是否是帮助解决整体问题的线索。

1 个答案:

答案 0 :(得分:0)

问题是app委托设置为MyDocumentNSDocument子类)。通过创建标准AppDelegate类(NSObject,实现NSApplicationDelegate协议),在XIB中创建相应的NSObject并将其设置为{{1}来解决问题然后将AppDelegate作为AppDelegate的委托。

我似乎问题的根源是MyDocument对象被解除分配,但它仍然是MyDocument子类的委托。然后NSWindow向委托发送了一封dealloc消息,但它已被解除分配,导致崩溃。

Here is the chain that solved it (long but instructive).