Site icon AppTractor

В iOS 26 SwiftUI наконец-то стал таким же быстрым, как UIKit?

Я люблю SwiftUI. Я ненавижу SwiftUI.

Я люблю UIKit. я ненавижу UIKit.

Когда ты так легко поддаёшься влиянию, как я, легко изменить своё мнение, основываясь на последней прочитанной статье в блоге.

SwiftUI всегда был на пути к паритету с UIKit, и на вопрос «готов ли SwiftUI к использованию в продакшене» уже много лет есть однозначный ответ: да, но.

Да, но для таких вещей, как камера, вам придётся перейти на UIKit.

Да, но отсутствует некоторая функциональность, например, UIScrollViewDelegate.

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

Производительность.

В частности, производительность прокрутки.

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

Но в этом есть доля правды:

Производительность — это последний бастион превосходства нативных iOS-приложений.

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

iOS 26 переходит грань: в разделе «Что нового в SwiftUI» на WWDC 2025 Apple посвятила половину времени объяснению улучшений, внесенных в обновления списков и производительность прокрутки в целом.

Эти улучшения не теоретические: в приложении Ice Cubes от Томаса Рикуарда значительно снизилось количество зависаний при прокрутке.

Давайте проверим заявления Apple в решающей битве свайпов.

Создание самого нелепого прокручиваемого представления, которое только можно себе представить

Если мы хотим осмысленно понять характеристики производительности прокрутки SwiftUI и UIKit, нам нужно действительно проверить их на практике.

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

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

Что нужно, чтобы сделать пользовательский интерфейс по-настоящему нелепым?

Но как этого добиться?

У меня есть идея. С небольшой помощью моего друга, CD-ROM «22,000 анимированных GIF-файлов» от 2001 года.

Теперь, когда у нас есть наш секретный ингредиент, я могу создавать два хаотичных пользовательских интерфейса одновременно на SwiftUI и UIKit.

Эти гифки просто безумны. И да, я произношу это точно так же, как и вы.

Сложность этого интерфейса заставляет экран стремиться к высокопроизводительной частоте обновления 120 кадров в секунду, оставляя всего 8,33 мс на рендеринг каждого кадра. От этого не спрятаться в моих профилях производительности.

Итак.

Раз и навсегда.

SwiftUI так же производителен, как UIKit?

Честный тест

Я учёный. Ну. Вроде того. Я получил степень по физике.

Бросил ли я учебу после трёхгодичного бакалавриата? Да. Но только потому, что я достаточно умен, чтобы понимать, что я недостаточно умен для магистратуры.

Я отвлёкся.

Чтобы обеспечить честный тест, мы хотим контролировать все переменные (Или это влияние переменных? Я отвлекся. Опять же).

В любом случае, я запускаю все на своем iPhone 17 с iOS 26.1. Вы можете сами провести точно такие же тесты, чтобы подтвердить (или опровергнуть!) мои результаты, используя проект с открытым исходным кодом.

Честно говоря, это стоит сделать хотя бы ради того, чтобы увидеть это разнообразие ретро-гифок.

Чтобы еще больше контролировать переменные, я поделился максимально возможным количеством кода. Примерно половина кода была выделена в общий публичный модуль, включая модель представления @Observable, используемую как UIKit, так и SwiftUI.

Я также использовал стороннюю библиотеку SwiftyGif для обработки GIF-анимаций. Мне не очень нравилось оборачивать GIF-файл в UIViewRepresentable, чтобы предоставлять к нему доступ SwiftUI, но небольшие накладные расходы были более предпочтительны, чем использование совершенно другой библиотеки.

Я применил несколько базовых приёмов повышения производительности, чтобы обеспечить совместимость с обоими UI-фреймворками:

При перемещении наших GIF-стикеров с помощью жестов мы записываем изменения в состояние модели только по завершении жеста (через updateSticker), а не по тику.

Теперь давайте проведём эксперимент.

Производительность SwiftUI (с использованием List)

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

Мы создали этот List для нашего пользовательского интерфейса ленты.

Теперь начнём профилирование.

Производительность анимаций с помощью Instruments

Инструменты можно найти в меню Xcode > Open Developer Tool. Для профилирования производительности анимации есть Animation Hitches, который содержит профили для задержек, зависаний, синхронизации дисплея и временных профилей.

Я провел один и тот же тест несколько раз:

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

Но это было еще не все. Когда я посмотрел на график работы, я почувствовал себя детективом, врывающимся на место преступления Джека-потрошителя.

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

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

Профиль памяти, процессора и температуры с Xcode

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

Использование памяти не было резким, но имело интересные скачки. Возможно, это связано с разным количеством GIF-файлов и разным разрешением изображений, отображаемых в каждой ячейке.

Производительность процессора и теплоотдача — это совсем другая история: теперь ясно, почему у нас было столько проблем. Даже в состоянии покоя, без прокрутки, процессор работал на 100% мощности, обрабатывая каждый GIF-файл, и значительно превышал 100% (распределяя работу между ядрами процессора) при прокрутке.

Уровень энергопотребления «Очень высокий» быстро нагрел мое устройство. Измеренная температурная кривая приблизилась к «Серьезному». Хотя я не обратил внимание, приложение даже было закрыто операционной системой, предположительно, из-за критического скачка температуры.

Инструмент SwiftUI Performance

Ладно, это было не идеально. Но, смотрите, новый инструмент!

Ладно. Это не совсем относится к этому тесту, но это приятно. Для Xcode 26 Apple создала совершенно новый инструмент для отладки медленных обновлений View в SwiftUI.

Как вы можете видеть здесь, выделенные проблемы с обновлением View точно совпадают с проблемами пользовательского интерфейса.

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

Производительность UIKit (с использованием UICollectionView)

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

Какое современное решение для достижения этого в UIKit? UICollectionView.

Давайте сразу перейдём к профилированию.

Производительность анимации с Instruments

Я провёл один и тот же набор тестов, одинаковое количество раз. Загрузка, прокрутка, прокрутка быстрее и игра с GIF-анимациями.

Признаюсь честно, я не отличаюсь особой наблюдательностью, но что-то было не так. Версия SwiftUI, ещё до просмотра трассировки и обнаружения зависания интерфейса, казалась необъяснимо… странной.

В версии UIKit таких проблем не было. Это какая-то фигня из Unreal Engine 5. Просто… ни одна часть моего подсознания не кричала во время прокрутки.

Что касается самой трассировки Instruments, UIKit почти не страдает.

В ходе моих тестов я зафиксировал 0,7 зависаний в секунду (по сравнению с 3,4 для SwiftUI).

Средняя продолжительность зависаний осталась прежней. Зависаний не было обнаружено, но наблюдалось несколько коротких (38 мс) задержек взаимодействия, выделенных серым цветом.

Профиль памяти, процессора и температуры с помощью Xcode

Что касается профилирования пикового потребления памяти и энергии, я ожидал тех же результатов, что и в SwiftUI: мы по-прежнему отображаем огромное количество элементов, анимируем их одинаково, и эти изображения не становятся ни больше, ни меньше, верно?

Теперь я выгляжу глупо.

Использование памяти в UIKit составляло около 92 МБ, по сравнению с 248 МБ в SwiftUI.

После серьезной нагрузки на мой новенький процессор A19, тот же самый поток данных в UIKit показал сравнительно незначительное использование ЦП и энергии.

Я перестал ждать, пока температурный профиль достигнет уровня «Fair» через 3 минуты.

Слон в комнате

Даже в iOS 26 SwiftUI значительно уступает UIKit по производительности прокрутки очень сложных пользовательских интерфейсов.

Но почему эта производительность отличается?

Возможно, вы думаете то же, что и я.

Разве List не реализован через UICollectionView внутри?

Вот наша версия UIKit в отладчике иерархии представлений, сияющая нашим вручную созданным UICollectionView:

На экране SwiftUI отображается загадочный объект UpdateCoalescingCollectionView.

Таким образом, это не стандартное представление коллекции. И производительность кардинально отличается.

Характеристики производительности SwiftUI в корне ограничены его архитектурой. Я всегда говорил, что прекрасный, реактивный, автоматический поток данных «из коробки» имеет свою цену:

Каким будет будущее SwiftUI?

Недавно Mastodon взбудоражил слух, которым поделился Стив Траутон-Смит:

Мне нравятся хорошие слухи, поэтому поделюсь вот этой новостью:

Я слышал, что SwiftUI теряет политический капитал и доверие внутри Apple, потому что неоднократно не соответствовал целям и потребностям разработки программного обеспечения. Он больше не считается очевидным выбором по умолчанию для новых разработок.

Это может объяснить, почему на WWDC ему уделялось меньше внимания, чем в последние несколько лет.

Интересные новости.

С нетерпением жду следующего выпуска статьи об использовании SwiftUI внутри Apple от Александра Колуччи. Мы можем проверить, подтверждается ли этот слух, посмотрев, стабилизировалось ли использование SwiftUI во внутренних бинарных файлах iOS.

Напоследок

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

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

Самым большим преимуществом SwiftUI всегда был быстрый и простой в написании декларативный синтаксис. Но с появлением Agentic Engineering, раздражающая перегрузка от написания программного кода UIKit стала незначительной.

Не хочу быть тем, кто это говорит, поэтому, пожалуйста, сделайте за меня эту работу и тихонько подтвердите это, идя на работу на этой неделе:

«SwiftUI мертв. Да здравствует UIKit!»

Источник

Exit mobile version