Качественное приложение не только хорошо выглядит, но и хорошо ощущается. Это включает в себя восхитительную анимацию, великолепный дизайн, удивительное взаимодействие и, возможно, самое главное — отзывчивость.
Скорее всего, слыша характеристику «отзывчивое», вы представляете себе приложение, которое всегда мгновенно реагирует на ваши действия. Например, прокручивая список в таком приложении, вы не заметите никаких задержек, сбоев или рывков, из-за которых прокрутка перестала бы ощущаться как полностью управляемая вами.
Когда приложения начинают расти в размере и усложняться, становится всё труднее решать проблемы производительности с помощью простых методов, таких как использование операторов вывода, чтение кода и тестирование приложения. Проблемы производительности, как и ваше приложение, становятся всё более сложными — а это означает, что появляется потребность воспользоваться более сложными инструментами для профилирования и проверки фиксов.
В этой статье мы рассмотрим, как можно использовать Instruments для получения новых и интересных данных о вашем приложении.
Сборка приложения и его запуск с помощью Instruments
Когда вы решите, что хотите профилировать приложение, вам нужно будет запустить его несколько иначе, чем обычно. Необходимо скомпилировать приложение, выбрав опцию Profile из меню Product или нажать горячие клавиши ⌘+I.
Выполнение этого действия по умолчанию приведёт к созданию приложения в режиме Release. Это означает, что приложение, которое вы профилируете, будет создано с использованием тех же параметров и конфигурации, что и приложение, которое вы поставляете своим пользователям.
Примечание: В этой статье я буду профилировать приложение с помощью симулятора. Instruments поддерживает профилирование приложений, работающих на вашем устройстве. Это всегда предпочтительный подход при профилировании приложения. Симулятор использует аппаратные ресурсы вашего Mac. Это означает, что результаты в Instruments иногда могут значительно отличаться от того, что происходит на реальном устройстве.
После создания приложения откроется приложение Instruments, и вы сможете выбрать один из различных шаблонов профилирования. Для профилирования приложения на SwiftUI нужно начать с выбора шаблона SwiftUI.
После выбора интересующего вас шаблона перед вами откроется главное окно Instruments. В левом верхнем углу находится кнопка записи. Когда вы нажмете её, ваше приложение запустится, и Instruments начнёт его профилировать.
На этом этапе вам нужно начать взаимодействовать с приложением и выполнять действия, которые вы хотите профилировать. Во время этого процесса Instruments будет записывать различные данные. Как только вы соберёте интересующие вас данные, вы можете нажать кнопку «Стоп» в левом верхнем углу окна Instruments, чтобы завершить запись.
Теперь, когда у нас есть данные для анализа, давайте изучим различные полосы информации, которые показывает Instruments, начиная с верхней.
Изучение полосы View Body
Самая верхняя полоса в SwiftUI Instrument — это View Body. SwiftUI записывает, к каким телам представлений был доступ и сколько времени заняло каждое обращение. Эта информация представлена на полосе View Body.
При выборе этой полосы Instruments покажет обзор тел представлений, которые были оценены во время всего периода записи. Если развернуть информацию, относящуюся к вашему приложению, вы сможете увидеть, какие из ваших представлений были оценены. Вы также увидите, как часто оценивался каждый подкласс представления, сколько времени заняли все оценки в совокупности, а также сколько времени заняло самое быстрое, самое медленное и средниее обращение к телу представления.
Если вас интересует профилирование конкретного взаимодействия, анимации или момента времени, это представление слишком широкое. В конце концов, он показывает все, что произошло за весь период записи.
К счастью, вы можете увеличить масштаб для определенной части записанных данных. Кликните в верхней полосе и перетащите, чтобы выбрать период времени. Нижняя панель теперь будет показывать только те оценки тел представлений, которые произошли в выбранный временной промежуток.
Каждый раз, когда SwiftUI оценивает тело представления, это говорит о нескольких вещах:
Одно или несколько свойств представления изменились.
Или один или несколько наблюдаемых объектов в представлении запустили свои «издатели» (publishers) objectWillChange.
SwiftUI выполнит работу по перерисовке этого представления.
Прежде чем SwiftUI оценит тело представления, он сравнит свойства представлений, чтобы убедиться в обоснованности предположения о том, что перерисовка представления приведёт к новому состоянию видимости.
Поэтому, если вы видите больше тел представлений, чем ожидали, или если вы видите тела представлений, в которых вы уверены, что данные не изменились, вы знаете, что искать. Что-то в вашем коде определённо меняется таким образом, что заставляет это представление изменить одно из своих свойств.
Сложность в том, что есть большая вероятность того, что ни одно из свойств представления на самом деле не изменилось. Вернее, ни одно из свойств, необходимых вашему представлению. Если ваше представление наблюдает наблюдаемый объект, но не использует некоторые из его @Published свойств, представление всё равно перерисуется, когда одно из этих неиспользуемых @Published свойств изменится.
Полоса View Bodies — это полезный инструмент, который поможет вам понять, не делает ли SwiftUI больше работы, чем должен.
Изучение полосы View Properties
Полоса View Properties («Свойства представления») поможет узнать, как ведут себя свойства вашего представления. На ней в виде списка отображаются представления, свойства представления и текущее значение этих свойств. Это позволяет проверить текущее состояние приложения в месте расположения маркера, показанного на рисунке ниже.
Кликните по различным точкам на промежутке времени, чтобы увидеть текущие значения состояния в месте расположения маркера.
Когда одно или несколько свойств вашего представления, связанных с состоянием, обновляются, вы сможете увидеть, как эти значения меняются при перемещении указателя воспроизведения. Это довольно удобно, но, к сожалению, вы не всегда можете чётко увидеть, какие свойства в каком представлении изменились. Вы можете различать свойства только по их типу, но неясно, когда два свойства относятся к одному экземпляру представления или к разным.
За этой полосой полезно следить, но она не даёт такого количества информации, как полоса тел.
Понимание полосы Core Animation Commits
Полоса Core Animation Commits содержит немного информации. Она показывает, сколько коммитов Core Animation Commits было сделано нашим приложением за выбранный промежуток времени, и сколько времени эти коммиты заняли.
Эта полоса особенно полезна для анализа, если возникают проблемы с производительностью интерфейса; и вы хотите выяснить, не являются ли определённые представления причиной тяжелых операций Core Animation Commit. Core Animation Commit приводит к тому, что GPU вашего устройства выполняет работу по перерисовке или обновлению экрана. Поэтому, когда вы видите Core Animation Commit, вы знаете, что имеете дело с перерисовкой.
Если вы замечаете, что происходит много коммитов или коммиты выполняются медленно, обратитесь к полосе View Bodies, чтобы выяснить, какие представления вызывают проблемы. Какие представления перерисовываются во время медленных коммитов? Если эти представления представляют собой огромную область в вашем макете или если они сложные и имеют большое тело, возможно, имеет смысл посмотреть, можно ли разделить это представление на более мелкие, которые наблюдают за меньшим количеством состояний.
Более мелкие представления в конечном итоге требуют меньше работы для оценки, а если они ещё и занимают меньше места в интерфейсе, то это означает, что потребуется меньше пикселей для отрисовки.
Полоса Core Animation Commits очень полезна для поиска и устранения крупных перерисовок, поскольку она достаточно ясно указывает на ресурсоёмкую работу с интерфейсом.
Понимание полосы Time Profiler
Полоса Time Profiler очень полезна, если вы хотите узнать, какие функции вызываются в вашем приложении во время анимации, в ответ на нажатие кнопки или при оценке тела представления.
Time Profiler делает моментальный снимок того, что происходит в вашем CPU с очень короткими интервалами. Эти интервалы настолько коротки, что мы можем с высокой точностью определить, сколько времени занял вызов определённой функции. Поскольку всё, что происходит на CPU, фиксируется, в полосе Time Profiler накапливается огромное количество данных.
Обычно вы ищете функции, существующие в вашем коде, чтобы понять, какие из них могут работать медленно.
Лучший способ отобразить собственный код на полосе Time Profiler — выбрать её, нажать на Call Tree в нижней части экрана, а затем выбрать следующие параметры:
Эти опции создают отличный обзор того, что происходит в вашем коде в каждом потоке. Развернув главный поток (Main Thread), вы увидите примерно следующее:
Вы сможете увидеть каждую функцию и замыкание, которые были запущены в течение выбранного периода времени, а также продолжительность выполнения кода. Обратите внимание, что вы не сможете легко увидеть количество запусков той или иной функции, поэтому лучше выбрать как можно меньший промежуток времени, в котором вы сможете проанализировать, что именно происходит в ответ, например, на нажатие определённой кнопки.
В заключение
Профилирование кода — это неотъемлемая часть создания чрезвычайно производительных приложений. На ранних этапах разработки вы можете использовать здравый смысл, глаза и небольшой рефакторинг для повышения производительности приложения.
Однако по мере роста сложности вашего приложения будет всё труднее и труднее уверенно рассуждать обо всём, что может делать ваше приложение в данный момент времени. На этом этапе Instruments послужит незаменимым инструментом, который поможет вам получить подробную информацию обо всём, что делает ваше приложение на SwiftUI.
Начните с поиска медленных тел представлений или тел представлений, которые оцениваются, когда вы этого не ожидаете. Затем посмотрите на полосу Core Animation Commits, чтобы понять, не приводит ли ваши действия к тяжёлым перерисовкам. Используйте View Properties, чтобы проанализировать обновления свойств и убедиться, что состояние вашего приложения выглядит более или менее ожидаемо. И наконец, обратитесь к Time Profiler, чтобы выяснить, можно ли оптимизировать какие-либо функции, чтобы они выполнялись быстрее.
Instruments предлагает множество других шаблонов и инструментов для профилирования, поэтому настоятельно рекомендуем изучить и их. Тем не менее, шаблон SwiftUI предоставляет отличный старт для изучения производительности вашего приложения.
Все актуальные методы и инструменты мобильной (и не только) разработки можно освоить на онлайн-курсах OTUS: в каталоге можно посмотреть список всех программ, а в календаре — записаться на открытые уроки.