Макрос #Preview в языке Swift предоставляет удобный способ создания и предварительного просмотра компонентов пользовательского интерфейса. Он позволяет разработчикам быстро и легко создавать превью для своих View, чтобы визуально оценить, как они выглядят и взаимодействуют. Механизм макросов доступен на любой версии iOS, главное использовать Xcode 15. Сейчас доступно много информации о том, как писать макросы, много примеров и на удивление хорошая документация. Сегодня мы будем не создавать свой макрос, а подробно рассмотрим приватные макросы, предоставляемые Apple, а именно #Preview. В целом это совершенно обычный макрос, но мы не знаем что у него внутри. Пока давайте добавим превью, используя новый макрос: Превью уже работает, и мы можем увидеть наше представление. Однако нас интересует совсем другое — результат работы нового макроса #Preview, а именно генерируемый код. Для получения полного результата выполнения макроса, включая новый сгенерированный код, требуется выполнить компиляцию исходного кода. После успешной компиляции будет создан расширенный код, который фактически и будет выполняться после этапа сборки приложения. Для просмотра сгенерированного кода можно использовать Xcode, нажав на Expand Macro: А для понимания, где генерируемый код располагается, мы можем воспользоваться командой swiftc: Не мог не отметить, что есть ещё вариант просмотра результата работы макроса с помощью тестов При запуске команды мы получим сгенерированный файл @__swiftmacro_04TestA4View33_DC5l7PreviewfMf0 по пути /var/folders/zd/gc5dlw40000gq/T/swift-generated-sources/. Открыв файл, мы увидим следующий код и сможем изучить результаты работы макроса (Xcode 15 Beta 2): Код получился довольно не большим, но давайте добавим разъяснения того, что в нём и зачем. Обратим внимание на два, практически одинаковых, объекта: struct $s04TestA4View3... и class $s04TestA4View3… Интересно что class доступен только для xrOS(VisionOS). Тяжело предположить зачем Apple сделала структуру и класс с одинаковыми параметрами, а не использовала просто структуру. Может быть class с пометкой @objcиспользуется для поиска Preview в runtime, но зачем тогда пракически идентичная структура - вопрос открытый. Начнем с протокола, которому соответствует struct $s04TestA4View3.... Это протокол PreviewRegistry, и мы можем просто посмотреть его документацию: Из нее мы узнаем, что этот протокол необходим для поиска превью во время выполнения. Назначение полей fileID, line и column достаточно сложно предположить. Возможно, они нужны для определения конкретного View для превью, если их несколько в одном файле. Интересно, что в PreviewRegistry у нас есть static var preview: Preview и в частности тип Preview. Информации о нём достаточно мало: Так как понять, что из себя представляет эта структура, мы пока не можем, то попробуем извлечь немного больше информации, используя инструмент для просмотра деталей объекта Mirror: Сопоставив данные из Mirror, я смог получить следующую структуру: Теперь с этим можно работать. Давайте рассмортим части Preview подробнее. Еще из интересного: в Preview есть переменная source: ViewPreviewSource, которая на самом деле является просто обёрткой для нашего представления. ViewPreviewSource используется как контейнер, в котором может лежать как SwiftUI View, так и UIKit UIView или UIViewController. Благодаря этому механизму достигается поддержка работы Preview с UIKit, чего раньше превью не поддерживали без использования дополнительных обёрток. Таким образом, приложение может эксплуатировать возможности обоих фреймворков и позволяет без проблем создавать превью интерфейсов без необходимости вводить дополнительные абстракции или преобразования. Снова обратившись к Mirror, получаем примерный вид ViewPreviewSource структуры: Понимание того, как Apple использует свои же нововведения, очень сильно помогает в работе над собственными решениями. Например, этот разбор я проводил для проекта: Он берёт реализацию превью от Apple и генерирует на их основе snapshot-тесты и демо приложение. Подробнее о Prefire можно узнать из доклада: Исходя из того что я нашёл выше, можно использовать генерируемый макросом код, а именно протокол PreviewRegistry, для поиска превью во всём приложении — и при нахождении превью, которое реализует протокол, генерировать тесты. Например, с помощью Sourcery мы можем найти все PreviewRegistry и получить нужные нам превью. Для Sourcery нужно будет создать специальный Stencil-шаблон (как это делать, я рассказал в видео выше). Вот так это может выглядеть (псевдокод): Таким образом, мы узнали немного больше о том, что происходит при работе макроса #Preview. Можно сделать вывод о том, что макросы существенно упрощают жизнь разработчика и Apple уже предлагает нам свои решения на основе макросов. В результате вместо громоздкого решения мы получаем более компактное и простое: Старое решение: Новое решение:  iOS lover