EXC_BAD_ACCESS 关闭 NSDocument 时 window(启用 ARC)
EXC_BAD_ACCESS when closing NSDocument window (ARC enabled)
我正在努力将基于文档的应用程序从垃圾收集(它 运行 在 10.6 下很好)转换为自动引用计数(试图让它编译并 运行 10.12) .当最后一个 window 关闭时,我得到一个一致的 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 完成的),我猜有某处正在进行的隐式释放。但是我不确定去哪里找。
在调试器中时,lldb
抱怨 main.m
崩溃:
return NSApplicationMain(argc, (const char **) argv);
如有任何帮助,我们将不胜感激。谢谢。
研究了很多,问题还是没有解决,不过我有一个线索:
感谢您的回复。是的,我现在假设这是一个内存管理问题。有办法追查罪魁祸首吗?在 Instruments 中使用 Zombies 似乎没有帮助:它指出了一个问题,但没有帮助我解决问题。也就是说,根据 Instruments,违规行似乎是“-[NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed:saveWindows:]”;但我从未发布过那条线。我在解决问题方面取得了一些进展。
我在文档中使用的结构是:
NSDocumentController
:默认,不子类化
NSDocument
:子类,MyDocument;也是 window 的代表
NSWindowController
:默认,不子类化
NSWindow
: MyDocument.xib
, MainMenu.xib
我尝试将打开 window 的委托设置为 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(或应用程序)可能正在向已释放的 window 发送消息。所以我尝试添加行(在上述方法的末尾):
[currentWindowController setWindow:nil];
这消除了崩溃,但引入了新问题(例如在尝试加载新文件时等)。但我想知道这是否是帮助解决整体问题的线索。
问题是应用委托被设置为 MyDocument
(NSDocument
subclass)。通过创建标准 AppDelegate
class(NSObject
,实现 NSApplicationDelegate
协议),在 XIB 中创建相应的 NSObject
并将其设置为输入 AppDelegate
,然后让 AppDelegate
成为 MyDocument
.
的代表
问题的根源似乎是 MyDocument
对象正在被释放,但它仍然是 NSWindow
subclass 的委托。 NSWindow
然后向委托发送了一个 dealloc 消息,但它已经被释放,导致崩溃。
我正在努力将基于文档的应用程序从垃圾收集(它 运行 在 10.6 下很好)转换为自动引用计数(试图让它编译并 运行 10.12) .当最后一个 window 关闭时,我得到一个一致的 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 完成的),我猜有某处正在进行的隐式释放。但是我不确定去哪里找。
在调试器中时,lldb
抱怨 main.m
崩溃:
return NSApplicationMain(argc, (const char **) argv);
如有任何帮助,我们将不胜感激。谢谢。
研究了很多,问题还是没有解决,不过我有一个线索:
感谢您的回复。是的,我现在假设这是一个内存管理问题。有办法追查罪魁祸首吗?在 Instruments 中使用 Zombies 似乎没有帮助:它指出了一个问题,但没有帮助我解决问题。也就是说,根据 Instruments,违规行似乎是“-[NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed:saveWindows:]”;但我从未发布过那条线。我在解决问题方面取得了一些进展。
我在文档中使用的结构是:
NSDocumentController
:默认,不子类化
NSDocument
:子类,MyDocument;也是 window 的代表
NSWindowController
:默认,不子类化
NSWindow
: MyDocument.xib
, MainMenu.xib
我尝试将打开 window 的委托设置为 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(或应用程序)可能正在向已释放的 window 发送消息。所以我尝试添加行(在上述方法的末尾):
[currentWindowController setWindow:nil];
这消除了崩溃,但引入了新问题(例如在尝试加载新文件时等)。但我想知道这是否是帮助解决整体问题的线索。
问题是应用委托被设置为 MyDocument
(NSDocument
subclass)。通过创建标准 AppDelegate
class(NSObject
,实现 NSApplicationDelegate
协议),在 XIB 中创建相应的 NSObject
并将其设置为输入 AppDelegate
,然后让 AppDelegate
成为 MyDocument
.
问题的根源似乎是 MyDocument
对象正在被释放,但它仍然是 NSWindow
subclass 的委托。 NSWindow
然后向委托发送了一个 dealloc 消息,但它已经被释放,导致崩溃。