ViewController в стеке навигации не отключается при извлечении, вызывая утечку памяти

#ios #swift #memory-leaks #retain-cycle

#iOS #swift #утечки памяти #сохранить цикл

Вопрос:

В моем приложении у меня есть RootViewController , из которого все мои ViewControllers являются подклассами. При разработке я обычно использую это в своем rootVC:

 deinit { 
    print("(type(of: self)) deinit")
}
  

так что я всегда могу видеть, когда какой-либо из моих ViewControllers отключается. Он печатает:

MyExampleViewController отключается

Сегодня я заметил, что один из них не отключился, когда я отошел от него. Давайте назовем это DetailViewController . Это совершенно обычный (корневой) подкласс ViewController, вставленный в основной NavigationController . При нажатии Back button в навигации он перемещается, но никогда не говорит, что он отключается. Это первый нажатый контроллер, поэтому я не могу открыть контроллер раньше, чтобы посмотреть, поможет ли это. Но любой контроллер, нажатый после DetailViewController того, как он будет отключен, будет исправлен при переходе назад и вперед.

Я решил проверить график памяти, поэтому я снова запустил свое приложение, нажал на DetailViewController , затем удалил его, щелкнув Back button в навигации, затем я нажал Debug график памяти.

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

При нажатии на него я вижу это:

График памяти DetailViewController Это единственный контроллер в крайнем правом углу. Я не так часто использовал график памяти, но я предполагаю, что «сплошные» белые линии являются сильными претензиями, а чуть более прозрачные (серые) линии являются слабыми претензиями. Это означает, что к моему контроллеру есть одно серьезное требование. Тот, что внизу.

Это нижняя строка: График памяти 2

Что это значит? Похоже, что у моего (пользовательского) NavigationController есть вызываемый массив _childViewControllers , который сохраняет мой извлеченный контроллер. Чтобы уточнить, у меня нет никаких сохраненных переменных в моем пользовательском NavigationController . Это только подкласс для переопределения 5 функций, вот и все. У меня около 20 разных ViewControllers устройств, которые выталкиваются и выталкиваются этим точно таким же пользовательским NavigationController, но у всех них нет проблем с этим.

Я неправильно читаю график? Должно быть другое сильное утверждение, которое не видно на графике, верно? Когда я «открываю» viewController , щелкнув Back , не следует ли viewController удалить мой _childViewControllers ?

Комментарии:

1. Похоже, что цикл сохранения, я думаю, что проблема связана с «DetailViewController», а не с вашим навигационным контроллером? Есть ли у вас какой-либо таймер, асинхронный обратный вызов, обработчик завершения или что-то, что может вызвать цикл сохранения?

2. Интересно.. да, у меня их довольно много. Есть ли способ сузить область, где может возникнуть проблема? Я предполагаю, что мне где-то не хватает [слабого я], если это так. Но разве я не должен каким-то образом определять это в графике памяти? Я вижу только объекты, содержащие ссылку на мои данные, но не какие-либо ссылки, на которые ссылается моя информация. Есть ли способ увидеть это, не переходя вручную ко всем сотням объектов в списке слева и не ища его?

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

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

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

Ответ №1:

Наконец-то понял. К сожалению, мне пришлось постепенно комментировать несколько сотен строк кода, пока я не узнал, когда он начал отключаться, когда ожидалось. Проблема заключалась в отсутствии [weak self] закрытия, что не было неожиданным, но это был совершенно другой класс, связанный через сложную иерархию.

Комментарии:

1. Утечки памяти являются худшими, но их всегда стоит искать.