Простой способ обнаружить retain cycle в UIViewController
Простой способ обнаружить retain cycle в UIViewController

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

Apple предлагает отличный инструмент для отладки утечек памяти. Часто для этого используется метод print в deinit.

deinit {
	print("deinit (self)")
}

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

Примечание

Если вы найдёте статью интересной, то в этом канале я пишу об iOS-разработке.


Более качественный способ

Можно использовать Symbolic breakpoint, чтобы обнаружить retain cycles для UIViewController. Это та же концепция, что print выше, но гораздо чище. Таким образом, вы не накидываете в код лишние print.

Простая инструкция

  • Перейдите в Breakpoint Navigator (меню View > Navigators > Show Breakpoint Navigator или ⌘ - command + 8). Кстати, для шорткатов можно использовать и это решение: вот оно.

  • Нажмите + и выберите Symbolic Breakpoint... or Menu Debug > Breakpoints > Create Symbolic Breakpoint...

Создание Symbolic Breakpoint
Создание Symbolic Breakpoint
  • Установите для Symbol значение -[UIViewController dealloc]

Установка значения Symbol
Установка значения Symbol
  • Нажмите  кнопку Add Action и установите звук Sound в (ну или любой другой, какой посчитаете нужным).

  • Добавьте ещё одно действие, нажав +.

  • Установите действие на Log Message и задайте сообщение, которое вы хотите вывести в консоль, когда сработает dealloc для View Controller. В моем случае я установил его в --- dealloc @(id)[

    Пример создания Log Message
    Пример создания Log Message
    • Отметьте опцию Automatically continue after evaluating actions, поскольку мы не хотим, чтобы дебаггер останавливался, когда сработает наш Symbolic Breakpoint.

    Отметьте чекбокс, чтобы не было остановки дебаггера (отладчика)
    Отметьте чекбокс, чтобы не было остановки дебаггера (отладчика)

    Обнаружение утечки

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

    Если вы выводите или удаляете ViewController, но не слышите соответствующего звука, это означает только одно — произошла утечка.

    Итак, что потребуется для обнаружения утечек

    Symbol[UIViewController dealloc]

    Module — пустой или UIKitCore

    Action:Soundpop или любой другой звук

    Action: Log Message--- dealloc @(id)[" class="formula inline">arg1 description]@ или любое другое сообщение

    Options можно установить Automatically continue after evaluating actions

    Примеры

    Пример раз

    Пример два

    Пример Apple


    Если вы нашли что-то полезное для себя, то подписывайтесь на мой канал, тут больше интересных историй и подходов.

    Авторский канал об iOS-разработке
    Авторский канал об iOS-разработке

Комментарии (3)


  1. aamonster
    25.04.2022 10:01
    +4

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

    Ну и отмечу, что удобнее просто использовать Instruments в XCode


    1. AlexWoodblock
      26.04.2022 07:25

      А еще symbolic breakpoints, если правильно помню, весьма медленные.


  1. Gargo
    26.04.2022 13:49
    +1

    этот трюк работает не всегда. Иногда какой-нибудь объект удерживает в памяти один view controller, а релизит другой. Мне попадались такие случаи:

    1)объект удерживает в памяти последний view controller, приложение релизит предпоследний view controller (если такой есть)

    2)объект удерживает в памяти первый view controller, приложение релизит все остальные view controllers

    Если применять способ из статьи, то придется следить за всем жизненным циклом view controller'а, потому что ошибка проявится только в самом начале.