Пользовательский NSViewController освобождается после того, как приложение переключается в фоновый режим и не может быть выпущено

Когда я переключаюсь на другое приложение, следующее взаимодействие с представлением иногда приводит к ошибке:

EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

Я переопределил метод deinit в CustomViewController, чтобы регистрировать сообщение при его вызове. Следующие сообщения регистрируются в консоли при возникновении вышеуказанной ошибки.

CustomViewController is being deallocated
*** -[AppName.CustomViewController release]: message sent to deallocated instance 0x604000121b80

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

Мое приложение Cocoa до сих пор относительно простое, все содержится в файле Main.storboard по умолчанию, созданном, когда я впервые создал проект, а затем обновил его. Нет пользовательской раскадровки или кода инициализации контроллера. Все просто загружается и отображается, когда я запускаю приложение, прежде чем нажимать свой собственный код.

У меня нет кода для публикации, который, как я думаю, может быть связан с проблемой.

В моем коде нет ссылок на раскадровку или контроллеры, которые создаются при загрузке. Мне не удалось найти никаких подробностей о том, что происходит под обложками, чтобы лучше понять, что может быть причиной проблемы.

Нет ничего, что выделялось бы как потенциально проблемная область, которую я должен выделить.

Ближайшая аналогичная проблема, которую мне удалось найти в Интернете, — это этот. Но в этом сценарии они инициализируют свой контроллер вручную из раскадровки и не управляют ссылками на созданные экземпляры. Решение действительно предполагает, что некоторая сборка мусора выполняется, когда приложение перемещается на передний план, что согласуется с тем, что я вижу, но не помогает мне решить проблему.

Другой показывает аналогичную ошибку, но с ошибкой метода сохранения, а не с выпуском. Опять же, это связано с программной загрузкой пера (в данном случае на iOS 5).

Ошибка появляется только тогда, когда я переключаю приложение обратно на передний план, и это похоже на попытку освободить уже выпущенный контроллер представления. Когда я устанавливаю точку останова в методе deinit, я вижу, что он вызывается для экземпляра в порядке, прежде чем вызов освобождения завершится ошибкой, потому что тот же самый экземпляр уже освобожден.

Учитывая простую настройку, я уверен, что делаю здесь некоторые неверные предположения. Любая помощь будет очень высоко ценится.

Использование Swift 4 на macOS 10.13.6 с Xcode 10.1




Ответы (1)


Следуя совету в этом ответе, я проследил проблему до пользовательского NSTableHeaderCell, в котором была ссылка на CustomViewController. Ошибка освобождения всегда была связана с попыткой освободить пользовательскую NSTableHeaderCell.

Я нашел две вещи, которые кажутся связанными:

  1. Во-первых, ошибка в моем коде. Каждый раз, когда я обновлял данные, которые влияли на столбцы NSTableView, я заново создавал и назначал новый пользовательский экземпляр NSTableHeaderCell, даже если он уже был назначен, поэтому многие из этих экземпляров зависали в ожидании сборки мусора.
  2. После устранения описанной выше проблемы сначала казалось, что проблема решена, но в конечном итоге она снова возникла через более длительный период времени. Глядя на время вызовов удержания/освобождения в шаблоне профилирования Instruments Zombies, кажется, что могла возникнуть проблема параллелизма, когда было выполнено несколько вызовов освобождения при освобождении нескольких NSTableViewCell, что снизило общее количество сохранений CustomViewController до нуля. а затем последующий вызов удержания откуда-то из оставшейся ссылки на зомби, который, как я полагаю, должен был произойти до последнего вызова освобождения.

Я не уверен на 100%, была ли это проблема параллелизма или нет, но изменение ссылки на CustomViewController в пользовательском NSTableViewCell на слабую ссылку, похоже, решило проблему.

Все еще кажется, что в моем коде все еще может быть проблема, которую я не отследил, и использование слабых ссылок просто обходит ее, но на данный момент я предполагаю, что это решено.

person Tee    schedule 02.12.2018