EXC_BAD_ACCESS при закрытии окна NSDocument (ARC включен)

Я работаю над преобразованием основанного на документах приложения из сборки мусора (оно отлично работало под 10.6) в автоматический подсчет ссылок (пытаясь заставить его скомпилировать и запустить для 10.12). Я получаю постоянный EXC_BAD_ACCESS, когда последнее окно закрыто. Статический анализатор ничего не помечает.

Я использовал инструменты для поиска зомби, и действительно, кажется, что освобожденному объекту отправлено сообщение 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);

Любая помощь будет принята с благодарностью. Спасибо.

После дополнительных исследований проблема все еще не решена, но у меня есть подсказка:

Благодарю за ваш ответ. Да, на данный момент я предполагаю, что это проблема управления памятью. Есть ли способ найти преступника? Не похоже, чтобы использование Zombies in Instruments помогало: оно указывает на проблему, но не помогает мне решить проблему. То есть оскорбительная строка в соответствии с инструментами выглядит так: «-[NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed:saveWindows:]»; но я никогда не выпускал эту строку. Я сделал то, что может быть небольшим прогрессом в выяснении вещей.

Структура, которую я использую в документе:

NSDocumentController: по умолчанию, без подкласса NSDocument: подкласс, MyDocument; также делегат окна NSWindowController: по умолчанию, не подкласс NSWindow: MyDocument.xib, MainMenu.xib

Я попытался установить делегат открытого окна на ноль следующим образом:

-(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];

Это избавляет от сбоев, но создает новые проблемы (например, при попытке загрузить новые файлы и т. д.). Но мне интересно, является ли это ключом к решению общей проблемы.


person Curious Yogurt    schedule 14.05.2017    source источник


Ответы (1)


Проблема заключалась в том, что делегат приложения был установлен как MyDocument (подкласс NSDocument). Проблема была решена путем создания стандартного класса AppDelegate (NSObject, реализующего протокол NSApplicationDelegate), создания соответствующего класса NSObject в XIB и присвоения ему типа AppDelegate, а затем создания AppDelegate делегата для MyDocument.

Мне кажется, что источником проблемы было то, что объект MyDocument был освобожден, но он все еще был делегатом подкласса NSWindow. Затем NSWindow отправил делегату сообщение об освобождении, но оно уже было освобождено, что привело к сбою.

Вот цепочка, которая решила эту проблему (длинная, но поучительная).

person Curious Yogurt    schedule 27.05.2017