Привет! Меня зовут Альберт, я занимаюсь iOS-разработкой в компании SimbirSoft! Хочу поделиться инструментами для дебаггинга iOS-приложений, которые юзаю лично сам. Любой разработчик наверняка знает, что создание высококачественного приложения требует не только написания кода. Одна из важнейших составляющих достижения успеха в этом деле — эффективная отладка. К счастью, существует множество инструментов, которые помогут быстро и эффективно диагностировать, а также устранять проблемы. В этой статье мы подробно рассмотрим нативные и сторонние инструменты, доступные для отладки iOS-приложений, как использовать эти инструменты для диагностики и устранения распространенных проблем. Если интересно, тогда ныряйте под кат.
Code debugging
1) print(...)
Нельзя упустить нашу классику – print, который можно использовать для наглядного отображения в выводе консоли. Например, когда мы хотим получать много данных при скроллинге и сразу же их анализировать.
Также есть аналоги print() – это debugPrint() и dump(). Они дают более подробную информацию, особенно dump() – его лучше всего использовать при распечатывании каких-либо объектов, так как предоставляемые им данные будут довольно структурированными.
Проставление принтов для вывода данных о scrollView при скроллинге:
Вывод в консоль данных о contentOffset, его bounds и frame:
2) LLDB
Наверняка все так или иначе работали с отладчиком с помощью простановки breakpoint'ов, а если кто-то до сих пор это не пробовал, то совершенно точно нужно начать использовать данный инструмент в дебаггинге своего приложения.
Важные шорткаты:
Command + Y – включение и выключение всех breakpoint'ов;
Command + 8 – открывает breakpoint navigator.
Команды:
po (print object) – дает возможность посмотреть данные об интересующем нас объекте. Вывод данных о scrollView с помощью команды po:
p (print) – компилирует код для вычисления выражения, поэтому она обрабатывает вызовы функций и вычисляемые переменные. Для некоторых классов использование p может отображать только местоположение указателя памяти или может отображать полностью развернутое представление всех атрибутов класса, что может содержать много ненужной информации. В таких случаях нужно использовать po.
Вывод данных о scrollView с помощью p команды, в которой содержится много ненужной для нас информации:
v (variable) – в Xcode 10.2 Apple добавили еще одну команду отладчика — v, которая работает быстрее чем еe предшественники, так как выводит в консоль значение переменной из текущей области видимости (в отличие от p и po) без компиляции выражения. Минус команды v заключается в том, что ее нельзя использовать с computed property.
Пример использования:
bt (backtrace) – используется для печати обратной трассировки текущего стека вызовов. Это особенно полезно, когда вы пытаетесь определить последовательность вызовов функций, которая привела к ошибке или исключению.
Наглядный пример использования bt:
Также можно посмотреть стек вызовов функций в панели debug navigator, где можно перемещаться по стеку и смотреть последовательность вызовов функций, которые были вызваны для достижения последней цели – кода на выставленном breakpoint'е:
Есть возможность смотреть значения с помощью Variable Viewer, не вводя ничего в консоль. Он находится левее от дебаг консоли:
expression – с помощью этой команды отладки можно подменять значения переменных. В примере ниже мы заменим название метеорита с помощью простановки breakpoint'a в нужном месте и использования команды expression:
Теперь посмотрим изменение в приложении после замены названия:
Имя успешно поменялось – это очень полезная команда, когда вы хотите протестировать отдельные элементы, функции в своем приложении не меняя исходный код. Кроме того, экономия времени и гибкость обеспечены.
Можно сократить слово expression и писать вместо этого "e", а также создавать переменные на уровне отладчика.
Например:
e let $someValue = "Some name"
e annotation.title = $someValue
Следующие команды, которые мы разберем, будут для перемещения по коду с проставленным breakpoint'ом. Начнем с базового – активацией или деактивацией всех проставленных breakpoint'ов. Конечно же, мы можем это делать и с помощью дебаг консоли:
breakpoint enable, breakpoint disable, breakpoint delete – позволяют включать, отключать и удалять брейкпоинты, что и понятно из названия:
Также это можно сделать с помощью мышки, наведя на breakpoint и нажав на него. Если нужен подробный список того, что можно сделать с breakpoint'ом, необходимо кликнуть на него правой кнопкой мыши.
breakpoint list – команда для просмотра текущих брейкпоинтов. Отображаются как включенные так и отключенные, также можно посмотреть без этой команды, зайдя в debug navigator в левой панели. Помимо визуального просмотра в debug navigator можно включать или выключать отдельные breakpoint'ы:
breakpoint modify – команда для изменений свойства существующего breakpoint'a. Полезно, когда вы хотите вызвать breakpoint только при каком-нибудь заданном вами условии. Это сильно сказывается на производительности, поэтому не стоит пренебрегать данной командой. Пример: breakpoint modify -c (id breakpoint'a, который мы можем взять с помощью команды breakpoint list) "(триггер для срабатывания breakpoint'a)", где флаг "-с" расшифровывается как condition.
Вызов команды breakpoint list в дебаг консоли для получения id:
Теперь мы знаем что id breakpoint'a == 2, можно задавать нужное нам условия триггера для breakpoint'a, а также проверить что условие проставилось с помощью команды breakpoint list:
Теперь данный breakpoint будет триггериться при contentOffset.y > 100 у scrollView. Также при команде breakpoint list мы видим, что у нас проставлен новый Condition.
Чтобы удалить условия для триггера breakpoint'a, необходимо отправить пустую строчку вместо условия:
Как мы видим, удаление условия триггера для breakpoint'a произошло успешно, и теперь breakpoint будет вызываться при любом contentOffset.y у scrollView.
Вот некоторые другие флаги, которые можно использовать с breakpoint modify:
-i: установить счетчик игнорирования для точки останова (т. е. количество раз, сколько breakpoint должен игнорироваться перед срабатыванием).
-s: установить новый скрипт для точки останова (который будет выполняться при достижении breakpoint'a).
-t: установить новый поток или очередь для применения breakpoint'a.
Эти флаги подробнее можно посмотреть в документации Xcode.
watchpoint set variable (your name of variable here) – используется для чтения или записи определенной переменной или адреса памяти:
Watchpoint может быть особенно полезен, когда мы хотим отслеживать изменения определенной переменной или адреса памяти во время выполнения программы или в ряде сценариев отладки. Например, когда мы подозреваем, что переменная неожиданно изменяется, или когда мы хотим отслеживать изменения переменной с течением времени. Также watchpoint можно проставлять из Variable View:
Если мы хотим активировать или деактивировать отдельный breakpoint, можно сделать это с помощью перехода на нужную строчку и нажатия хот-клавиш "cmd + \".
Кнопки в панели отладки для управления выполнения программы, которые можно вызывать как с помощью нажатия, так и с помощью дебаг консоли:
continue – используется для возобновления выполнения и перехода к следующей точке останова (при ее наличии) или паузы приложения, если в данный момент приложение запущено, и мы нажмем на данную кнопку в панели отладки.
next – используется для выполнения кода по одной строке за раз, не входя внутрь вызовов функций.
step – для перехода в вызванную функцию на текущей строке.
finish – для завершения выполнения текущей функции и возвращения к вызывающей функции, если такая имеется. Если нет, тогда к возобновлению приложения.
Пример использования данных команд в дебаг-консоли:
Команды LLDB — это мощные инструменты, позволяющие нам взаимодействовать с программой во время ее выполнения в отладчике Xcode. С помощью команд LLDB мы можете устанавливать точки останова, проверять переменные и память, а также пошагово выполнять код построчно, чтобы выявлять и устранять проблемы. Изучив и освоив эти команды LLDB, можно быстрее решать проблемы в своем коде. Скорость работы с командами приходит с практикой и опытом, кроме этого разработчик понимает, что и для какой проблемы лучше всего использовать.
View Debugging
1) Debug View Hierarchy
Позволяет проверять иерархию представлений нашего приложения во время его работы, в симуляторе или на физическом устройстве. Бывает полезно для отладки проблем с макетом и понимания того, как разные представления накладываются друг на друга.
Чтобы включить инструмент, во время использования приложения нужно нажать на указанную кнопку:
Давайте разберем Debug View Hierarchy на примере выявления бага, я заметил, что contentOffset scrollView.y начинается не с 0, как это ожидается, а с -97.
Смотрим, что у нас не так (рис. 22). Можно заметить, что topAnchor у collectionView сэттится без safeArea, соответственно, contentOffset.y сдвигается и CGFloat = -97, чтобы пофиксить данный баг, нужно закрепить верхнюю часть к safeArea.
Баг пофикшен после изменения topAnchor у collectionView с закреплением по safeArea, теперь contentOffset.y начинается как и ожидается с 0:
2) Slow Animations
Это инструмент для замедления анимации в приложении. Часто применяется, чтобы отловить блики и разные баги связанными с UI. Для включения запустите приложение, далее перейдите из симулятора в Debug на верхней панели и нажмите Slow Animations (отключается так же, как и включается):
3) Color Blended Layers
Инструмент, позволяющий выявить проблемы с UI. Когда данный инструмент включен, то выделяются размеры всех элементов UI вашего приложения, отчего дебаггинг по UI-части становится проще. Особенно помогает, когда на экране много элементов:
Чтобы включить Color Blended Color, нужно перейти в Debug на верхней панели:
4) Reveal
Сторонний инструмент для визуальной отладки, который проверяет и изменяет представления и иерархию представлений нашего приложения во время выполнения. Он предлагает ряд функций для выявления и устранения проблем с layout'ом, включая возможность редактирования contraints, настройки позиций views. Обычно используется в том случае, когда нужны более продвинутые возможности. Это приложение платное, но есть пробный период, более подробно с ним можно ознакомиться на официальном сайте. Курс по Reveal от RayWenderlich.
Отладка проблем UI является важным навыком для IT-специалиста. Понимая инструменты дебаггинга UI, разработчики могут быстро диагностировать и устранять проблемы. Нативный инструмент, такой как Debug View Hierarchy, дает понять иерархию представлений нашего приложения, в то время как сторонние инструменты, такие как Reveal, предлагают более продвинутые функции, например, возможность прямого редактирования свойств представления. Также помогают и мини-инструменты, такие как «Color Blended Layers» или «Slow Animations». Используя комбинацию этих инструментов, время на отладку UI сократится, а приложение будет выглядеть и работать эффективнее, обеспечивая лучший пользовательский интерфейс для своих клиентов.
Memory Debugging
1) Memory Graph Debugger
Инструмент в составе Xcode, помогающий разработчикам диагностировать проблемы с памятью в своих приложениях для iOS. Он обеспечивает визуальное представление графа объектов в памяти, позволяя разработчикам видеть, как объекты связаны и как они взаимодействуют друг с другом. Анализируя этот график, специалисты могут выявлять утечки памяти, циклы хранения и другие проблемы, которые могут повлиять на производительность приложения.
В целом Memory Graph Debugger — это мощный инструмент для любого iOS-разработчика, для того чтобы диагностировать и устранять проблемы, связанные с памятью в приложении.
Для его активации во время использования приложения нажмите на следующую кнопку:
Так выглядит интерфейс при использовании приложения с данным инструментом:
Мы уже подробно разобрали Memory Graph Debugger в статье, где также приведены практические способы его применения.
2) Debug Navigator
Memory Report
Чтобы его открыть, во время использования приложения перейдите в Debug Navigator -> Memory Report:
Здесь мы можем видеть, как работа с приложением влияет на объем использования памяти, что поможет определить утечки памяти и другие проблемы, например, при каких действиях растет память.
Помимо Memory Report имеется еще 4 инструмента:
CPU – показывает процент использования центрального процессора нашим приложением с разбивкой по потокам. Помогает определить производительность в разных местах нашего приложения.
Energy Impact – показывает энергию, затрачиваемую приложением на устройстве пользователя в процентах. Служит для оптимизации приложения, если оно забирает много энергии.
Disk – показывает объем активности диска с разбивкой по операциям чтения и записи. Это может помочь нам определить проблемы с файловым вводом-выводом, которые замедляют работу приложения.
Network – показывает объем сетевой активности, генерируемой приложением с разбивкой по запросам и ответам. Позволяет определить проблемы с производительностью сети, которые могут замедлить работу приложения.
Управление памятью является важным аспектом разработки приложений. Проблемы, связанные с памятью, такие как утечки и чрезмерное использование памяти, могут привести к сбоям и отрицательно сказаться на производительности. К счастью, Xcode предоставляет несколько инструментов и методов для отладки проблем с памятью в приложениях iOS. Кроме того, хорошие привычки управления памятью, например, использование слабых ссылок, избегание ретэйн-циклов и внимательное отношение к использованию памяти, может помочь предотвратить возникновение проблем.
Network Debugging
1) Charles
Это популярный инструмент для отладки iOS-приложений, поскольку позволяет проверять сетевой трафик между нашим приложением и network-частью. Вот шаги, которые нужно выполнить, чтобы использовать
Charles для отладки на реальном устройстве:
Скачать приложение на macOS.
Зайти в Keychain и вбить в поиск «Charles» (рис. 30).
Проставить «Всегда доверять» для данного сертификата:
4. Включить macOS Proxy, перейдя по верхней панели на вкладку Proxy:
5. В той же вкладке зайти в SSL Proxying Settings и разрешить SSL Proxying, снизу можно проставить, откуда вы хотите снифферить трафик, в моем случае стоит перехват всего приходящего трафика:
6. Скопировать наш ip. Его можно найти как в настройках, так и в приложении Charles, в верхней панели перейдя во вкладку Help и выбрав Local IP Address:
7. У компьютера и мобильного устройства должна быть общая сеть, нам нужно перейти в настройки данного Wi-Fi:
8. Внизу в настройках есть Configure Proxy, переходим туда, проставляем Port - 8888, в Server вводим наш ip, который по посмотрели ранее:
9. Заходим в браузер с мобильного устройства и вводим charlesproxy.com/getssl, скачиваем сертификат для телефона.
10. Заходим в настройки, переходим во вкладку General, оттуда – в VPN & Device Management, где видим свой скачанный сертификат. Его нужно верифицировать. Для этого переходим по нему и устанавливаем, вводим пароль.
11. Снова переходим во вкладку General, оттуда в About, скроллим в самый низ, переходим в Certificate Trust Settings и проставляем доверие данному сертификату.
12. Готово! Теперь можно сниффить трафик с устройства. Не забудьте поставить proxy обратно в Automatic-режим после использования Charles, чтобы все работало корректно.
13. Если же вы сниффите трафик через симулятор, то все еще проще, вам просто нужно скачать сертификат с сайта и проставить его, как мы это делали в пунктах 9-12.
14. Проверяем, что от телефона все корректно приходит с помощью захода в приложение Windy о прогнозах погоды.
15. Теперь мы видим, что нам приходит и по необходимости можем посмотреть json, который нам приходит:
2) Postman
Это инструмент, который приходит на замену Charles, когда мы хотим просто и быстро протестировать эндпоинт и, например, получить развернутый json. Скачиваем с официального сайта, настраивать ничего не нужно, интерфейс супер фрэндли. Просто вбиваем нужный эндпоинт и получаем результат. Конечно, у него есть и другие инструменты, но в большинстве случаев для разработчика при дебаггинге этого функционала вполне достаточно. Еще очень удобно крепить нужные вам эндпоинты для дальнейшего переиспользования.
3) Network Link Conditioner
Полезный инструмент для симуляции плохой сети, когда нужно проверить что будет происходить с приложением с неустойчивым интернетом.
Взаимодействие на симуляторе:
1. https://developer.apple.com/download/all/ – переходим по ссылке, авторизируемся, вбиваем в поиск и выбираем нужную нам версию Xcode:
2. Переходим в папку, которую скачали, заходим в папку Hardware и далее в Network Link Conditioner.prefPane:
3. После ввода пароля для разрешения на добавление Network Link Conditioner у нас появляется данный инструмент в настройках:
4. Интерфейс очень понятный, главное не забывать выключать настройки Network Link Conditioner после использования. После проставления нужных настроек можно переходить в симулятор и выполнять необходимые задачи.
Взаимодействие на физическом устройстве:
1. Переходим в Settings -> Developer -> Network Link Conditioner.
2. Проставляем нужные настройки и проставляем switch on для enable.
3. Готово. После использования не забудьте проставить switch off для enable.
Throttle Settings в Charles:
1. Нужно настроить Charles, как это было описано выше.
2. Перейти в Proxy -> Throttle Settings в верхней панели поставить галочку на Enable Throttling:
3. Готово, можно выполнять нужные нам задачи.
Стоит отметить, что эффективность на физических устройствах iOS может быть ограничена сетевыми условиями между девайсом и компьютером, на котором работает Charles. Поэтому нативные инструменты более стабильны. Не забудьте убрать галочку на Enable Throttling после использования.
Отладка сети – это очень важный и частый процесс разработки приложений, поэтому нужно уметь работать с вышеописанными инструментами.
Time Profiler
Инструмент для анализа производительности, позволяющий записывать и анализировать время, потребляемое потоками и функциями нашего приложения. Также можно наблюдать за нагрузкой на CPU.
Инструмент для анализа производительности, позволяющий записывать и анализировать время, потребляемое потоками и функциями нашего приложения. Также можно наблюдать за нагрузкой на CPU.
Для использования нужно запустить приложение, перейти в Xcode -> Open Developer Tool -> Instruments. Из предложенных инструментов выбираем Time Profiler:
Нас не интересует все остальное, кроме Time Profiler, поэтому убираем из левого списка ненужное с помощью нажатия на инструмент + кнопки backspace. Для активации инструмента нажмите на красную кнопку для начала записи сессии:
Теперь Time Profiler делает snapshot'ы вашего приложения для анализа, стоит отметить, что мелкие функции могут не попасть в snapshot и, соответственно, вы их не увидите, но это не значит что функция не вызывалась, просто у Time Profiler'a не вошло это в snapshot. Справа в колонке «Heaviest Stack Trace» находятся трэйсы. Слева в колонке «Symbol Name» мы можем выбрать что нас интересует и посмотреть об этом информацию. Зачастую нужны только вызовы с изображением профиля, означающие, что вызов был от наших функций, а не от чего-то стороннего. Поэтому в большинстве случаев можно скрывать системные вызовы. Чтобы это сделать, нужно перейти в Call Tree и проставить галочку для Hide System Libraries:
Time Profiler можно ставить на паузу или закончить сессию с помощью кнопок в верхнем левом углу.
Давайте разберем пример на практике. Для этого я добавлю сложное действие с помощью цикла итерации большого числа. Метод makeSomethingHard забирает очень много времени, и мы видим, как растет в эти промежутки нагрузка на CPU. Также можно заметить колонку Hangs, где оранжевым цветом показано, сколько висело наше приложение, где пользователь не мог делать никаких действий, из-за того что main очередь была заморожена благодаря сложному вычислению на ней. Также можно проанализировать колонку Weight, где показано как нагрузка в процентах увеличилась после выполнения метода viewDidLoad, где был вызван метод makeSomethingHard. Соответственно, сделать вывод по имеющимся проблемам:
После того как метод makeSomethingHard был удалён, производительность стала стабильна:
Просмотрев данные, предоставленные Time Profiler'ом, разработчики могут принимать обоснованные решения о том, на чем сосредоточить свои усилия по оптимизации и сделать свои приложения быстрее и эффективнее.
Animation Hitches
Инструмент, который может помочь вам выявить и диагностировать проблемы с производительностью, связанные с анимацией в вашем приложении iOS. Он предоставляет подробную информацию о частоте кадров и использовании CPU во время воспроизведения анимации, а также представление временной шкалы, которое выделяет продолжительность и местоположение задержек анимации или моменты, когда воспроизведение анимации задерживается. Animation Hitches поможет определить основные причины проблем с производительностью, связанных с анимацией, и оптимизировать ее производительность для более плавного взаимодействия с пользователем.
Запустите приложение, перейдите в Xcode -> Open Developer Tools -> Instruments. Из предложенных инструментов выберите Animation Hitches.
Запускается так же, как и Time Profiler – через красную кнопку. Далее после использования приложения нужно закончить запись, нажав на квадрат в верхнем левом углу.
Чтобы привести пример использования, добавил в реюз ячейки коллекции сложную операцию на главной очереди. После сделанной записи в Animation Hitches при просмотре видно, насколько все плохо:
В Animation Hitch можно очень хорошо смотреть работу трэдов, за что он точно заслуживает места в инструментах разработчика.
Заключение
Итак, можно сказать, что отладка приложений – это целое искусство и очень полезный навык для любого разработчика :)
В этой статье мы разобрали множество инструментов дебаггинга. Надеюсь, вы нашли для себя что-то новое и полезное, что поможет улучшить качество вашей разработки и сократит потраченное время.
Если у вас есть пожелания по обзору других iOS-инструментов или по новым темам для наших статей, пишите в комментариях.
Спасибо за внимание! Хорошего кодинга :)
Больше полезных материалов для mobile-разработчиков мы также публикуем в наших соцсетях – ВК и Telegram.