Все записи

Автоматическая генерация UI-настроек

Меня зовут Илья, я мобильный разработчик в Naumen. Моя основная специализация — iOS‑разработка. Я занимаюсь развитием мобильного клиента платформы Naumen Service Management Platform, а также Chat SDK в рамках Naumen Contact Center.

Илья.jpg

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

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


Как из обычной задачи выросла проблема с настройками

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

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

Для разработчика это не так критично — пересобрать проект через Xcode можно за несколько минут. Однако в работе участвуют и другие роли:

  • аналитики на приемке

  • тестировщики при тестировании

Каждое изменение параметров означало необходимость пересборки приложения. В итоге тестирование любой мелкой настройки превращалось в цепочку действий с участием разработчика.

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


С какой еще проблемой мы столкнулись

Сначала мы решили сделать экран настроек с переключателями, полями ввода и другими UI‑элементами, однако столкнулись со следующей ситуацией.

Каждый раз, когда появляется новая настройка или меняется существующая, разработчику нужно:

  • добавить свойство в модель настроек
  • добавить UI‑компонент на экран
  • прописать обработку
  • связать все с системой хранения
Это неудобно по нескольким причинам.

  1. Растет объем дублирующего кода

  2. Тратится дополнительное время

  3. Любое расширение экрана требует новых изменений в кодовой базе  

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

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


К какому решению в итоге мы пришли

В поиске решения я вспомнил о механизме Reflection, в других языках этот механизм может называться Introspection. Он позволяет анализировать структуру объектов во время выполнения программы.

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

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

Что меняется в подходе

Если коротко, идея такая: разработчик больше не описывает каждый UI‑элемент экрана отдельно вручную. Вместо этого он задает свойства объекта настроек и добавляет к ним нужные метаданные. Дальше система сама анализирует эти данные и генерирует соответствующие компоненты интерфейса.

генерация UI 1.png

Из чего состоит такая система

1. Метаданные настроек

Каждая настройка описывается как свойство объекта. Дополнительно используются аннотации, которые содержат метаданные:

  • читаемое название свойств настроек

  • зависимости между настройками

  • дополнительные параметры отображения

2. Механизм анализа типов данных (интроспекция)

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

Он проходит по всем свойствам объекта настроек и извлекает:

  • тип данных конкретной настройки

  • метаданные из аннотаций

Полученная информация используется для построения интерфейса.

3. Система соответствия типов данных и UI-компонентов

Дальше система определяет, какой UI‑компонент нужен для конкретного типа.

Например:

  • для Bool — переключатель

  • для текстового значения — поле ввода

  • для числового значения — тоже поле ввода, но уже с ограничением на числовой ввод

За счет этого интерфейс строится не вручную, а на основе правил сопоставления.

4. Система обработки событий взаимодействия и UI-компонентов

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

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

5. Система хранения и восстановления настроек

Чтобы настройки могли сохраняться между запусками приложения, можно использовать систему хранения. Она должна уметь сохранять данные при их изменении и восстанавливать при перезапуске системы.


Как выглядит процесс сборки экрана

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

Сама сборка делится на четыре этапа: анализ объекта настроек, генерация UI‑модели, создание интерактивного интерфейса и обработка изменений.

генерация UI 2.png

Этап 1. Анализ объекта настроек

  • Получение метаинформации об объекте настроек с использованием интроспекции

  • Обход всех свойств объекта

  • Извлечение типов данных и метаданных из аннотаций


Этап 2. Генерация UI-модели

  • Создание секций настроек на основе группировки по объектам настроек

  • Генерация UI-моделей компонентов для каждого типа данных

  • Настройка связей между компонентами — зависимости

  • Применение метаданных — названия


Этап 3. Создание интерактивного интерфейса 

  • Создание UI-элементов на основе сгенерированной модели

  • Настройка обработчиков событий для каждого компонента

  • Связывание с системой хранения для сохранения изменений

  • Реализация зависимостей между настройками


Этап 4. Обработка изменений ё

  • Перехват пользовательского ввода через обработчик событий
  • Валидация данных в соответствии с типом
  • Сохранение в хранилище с сериализацией
  • Обновление зависимых настроек при необходимости

Как это реализовано в Swift

Метаданные через Property Wrappers

Для добавления метаданных мы используем механизм Property Wrappers. Он позволяет обернуть свойства в дополнительную логику и сохранить прозрачный доступ к значению. Property Wrappers идеально подходит для нашего случая, так как он может добавлять метаданные прямо в объявление свойства, а не где‑то в отдельной части кода.

Снимок экрана 2026-03-20 в 12.55.36.png

Анализ типов через Mirror

Для интроспекции используется Mirror API. Это встроенный механизм рефлексии, который позволяет анализировать структуру объектов во время выполнения.

А еще с помощью механизма можно:

  • автоматически обнаружить все свойства объекта настроек
  • извлечь их типы и метаданные
  • построить на основе этой информации UI‑модель

Снимок экрана 2026-03-20 в 12.57.30.png

Генерация UI-компонентов

Для построения интерфейса можно использовать:
  • UIKit
  • SwiftUI
В нашем проекте используется UIKit. В целом такой подход можно реализовывать и через SwiftUI, потому что декларативная модель там тоже хорошо ложится на идею автоматической сборки интерфейса. Но в нашем случае выбор UIKit продиктован самим проектом.

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

Снимок экрана 2026-03-20 в 12.58.36.png

Обработка событий

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

В Swift мы используем стандартный подход с назначением действия на UI‑компоненты — это классический подход iOS‑разработки. Каждый UI‑компонент может иметь целевой объект и действие, которое выполняется при взаимодействии. В других языках программирования эта задача чаще всего решается с помощью callback'ов.

Каждый UI‑компонент получает свое действие на изменение значения. Дальше система должна правильно интерпретировать пользовательский ввод и привести его к нужному типу. 

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

Снимок экрана 2026-03-20 в 12.59.52.png

Хранилище и восстановление данных

Для хранения настроек в Swift мы используем:
  • UserDefaults — для простых типов данных
  • NSKeyedArchiver — для преобразования сложных объектов в данные
Важно, что система хранения должна быть устойчивой к ошибкам. Данные могут повредиться, не загрузиться или отсутствовать вовсе. В таком случае настройки все равно должны отображаться и корректно работать со значениями по умолчанию.

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

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

Снимок экрана 2026-03-20 в 13.00.47.png

Снимок экрана 2026-03-20 в 13.01.41.png

Пример добавления настройки: изначальное описание объекта настроек и то, что пользователь увидит в приложении


Важное ограничение Swift, которое пришлось обойти

Здесь есть принципиальный момент. В Swift рефлексия ограничена: она не позволяет изменять значение напрямую через механизм интроспекции.

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

Снимок экрана 2026-03-20 в 13.04.28.png

Пример добавления новой настройки для отображения вкладки с чатом — она связана с отображением таббара. Включение и отключение настройки отображения таббара влияет на настройку открытия вкладки с чатом в таббаре


Что дает такой подход на практике

Поддержка разных языков

Подход легко переносится на другие языки программирования, где поддерживается интроспекция данных.

генерация UI 3.png

Расширяемость системы

Чтобы добавить новый тип в обработку, достаточно:
  1. Добавить новый тип данных в анализатор
  2. Создать соответствующий UI‑компонент
  3. Настроить обработку взаимодействия с данным компонентом
  4. После все свойства этого типа автоматически появятся на экране настроек.

Сокращение трудозатрат

Трудозатраты на добавление новых настроек сокращаются примерно на 80–90% по сравнению с ручной реализацией экрана и самих настроек. Разработчику достаточно описать новое свойство с аннотацией, и оно автоматически появляется в интерфейсе.

генерация UI 4.png

Уменьшение объема дублирующего кода

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

Типобезопасность

Если системе встретится неподдерживаемый тип данных, это не приведет к падению приложения: такая настройка будет пропущена и не отобразится, пока для нее не добавят нужную обработку.

Консистентный интерфейс

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

Подход с автоматической генерацией UI-настроек через интроспекцию типов позволяет сократить объем ручной работы и дает разработчику возможность уделять больше времени бизнес-логике, а не ручному созданию интерфейсов.

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

Похожие новости

ИИ-помощник для анализа требований

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

Когда таких документов много и нужна оперативность, ручная обработка начинает замедлять работу команды. С этим регулярно сталкивалась команда техпресейла Naumen. Поэтому Настя и Даша, системные аналитики команды, решили попробовать автоматизировать часть процесса и внедрили ИИ-помощника для анализа требований.

В статье рассказываем, как они собирали данные, какие подходы пробовали и как в итоге пришли к решению на базе RAG.

Как перестать тратить полдня на один вопрос в чате

Рабочий вопрос, который в офисе решается за пять минут, в онлайне иногда превращается в переписку на полдня: написал в чат → подождал → уточнил → снова подождал. 

Мы обсудили эту тему с Димой — бизнес-аналитиком команды внедрения. В его работе коммуникации занимают значительную часть дня: с клиентами, разработчиками и внутри команды. 

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

Как видеть будущее и превращать его в продукты и стратегии

Рынок цифровых продуктов меняется быстро, а требования к продуктовым командам постоянно растут. Чтобы принимать стратегические решения, важно понимать, какие изменения происходят на рынке и какие тренды будут определять его развитие.

Ксюша, руководитель продукта Project Ruler, рассказала о практическом подходе к трендвотчингу: где искать ранние сигналы, как отличать краткосрочные всплески интереса от устойчивых тенденций и какие изменения уже заметны на рынке систем управления проектами.

Все новости