Почитал интересную статью от Two Cent Studios про контейнер Group в SUI – и она очень точно формулирует проблему, с которой многие сталкивались, но не сразу могли понять.
В SUI Group часто воспринимается как способ логически сгруппировать несколько View.
Он не участвует в layout и не появляется в иерархии, а лишь влияет на то, как SUI обрабатывает вложенные элементы.
И именно эта неочевидность часто становится источником проблем.
Group {
if isLoading {
ProgressView()
} else {
ContentView()
}
}
.onAppear {
fetchData()
}Интуитивно кажется, что fetchData() вызовется один раз – при появлении Group.
Но на практике SUI распространяет onAppear на каждое View внутри Group.
В результате fetchData() может вызваться и для ProgressView, и для ContentView.
То есть логика внезапно начинает жить в двух местах, хотя визуально это вообще не очевидно.
Ключевая мысль статьи сводится к следующему:
Group чаще всего используется там, где логически должен быть отдельный View.
⚠️ Почему Group так легко превращается в проблему
- Group не изолирует логику
- Group не изолирует модификаторы и автоматически применяет их ко всем вложенным View
- скрывает реальную структуру экрана
- усложняет понимание body, особенно при условиях
Код выглядит компактно, но становится менее предсказуемым.
1. Вынос в отдельную View
Вместо:
Group {
Text("Title")
Text("Subnoscript")
}
.foregroundStyle(.red)Лучше:
HeaderView()
.foregroundStyle(.red)
- лучше читается
- проще переиспользовать
- легче тестировать
2. Реальные layout-контейнеры
Если важно именно как элементы располагаются на экране, а не просто сгруппировать код – подойдут:
- VStack
- HStack
- ZStack
- Grid
- Section
Они явно показывают структуру интерфейса, а не маскируют её.
3. ViewBuilder
Если Group появляется просто потому, что body стал слишком большим – это хороший сигнал к декомпозиции, а не к ещё одному уровню вложенности.
Group не решает задачу структуры интерфейса.
Он лишь влияет на то, как SUI обрабатывает вложенные View, не делая это очевидным из кода.
В результате логика жизненного цикла и применение модификаторов становятся менее прозрачными.
Практическое правило простое:
если в коде появляется Group, стоит проверить, не напрашивается ли здесь отдельный View.
#R #SwiftUI
Please open Telegram to view this post
VIEW IN TELEGRAM
💯5❤3🔥2
Многие команды внедряют достаточно сложные архитектуры (VIPER, Clean Architecture), которые признаны неким стандартом, но которые не решают их реальных задач, при этом увеличивают объем кода, время сборки проекта и время погружения разработчиков. Но идеальная архитектура это та, которая соответствует размеру команды и сложности бизнес-процессов.
Мистер Хотфикс проанализировал 147 iOS проектов и сделал для нас много интересных выводов.
Что говорит статистика?
- Распределение: MVVM (41%), MVC (34%), VIPER/Clean (18%), TCA (5%), another (2%).
- Проблема: 73% проектов используют архитектуры, которые не решают их фактические проблемы.
- Последствия чрезмерного проектирования: Внедрение Clean Architecture в средних командах часто ведет к росту объема кода на 143%, замедлению разработки на 67% и увеличению времени онбординга новых разработчиков до 3 недель.
Какие архитектуры популярны?
- MVC (Model-View-Controller):
Когда работает: Команды 1–3 человека, простые приложения.
Проблема: Massive View Controller возникает не из-за самой архитектуры, а из-за неумения выделять сервисы (у 89% проблемных приложений).
- MVVM (Model-View-ViewModel):
Когда работает: Золотая середина для команд 3–10 человек, особенно в SwiftUI.
Плюсы: Повышает покрытие тестами до 67% (против 23% в MVC) при умеренном росте кодовой базы (+35%).
- VIPER / Clean Architecture:
Когда работает: Команды 15+ человек, финансовые/медицинские приложения с ценой ошибки в миллионы.
Минусы: Экстремальный избыток кода (одна фича может занимать 7 файлов и 730 строк кода против 3 файлов и 260 строк кода в MVVM).
- TCA (The Composable Architecture):
Когда работает: Команды уровня Senior, которым нужна 100% тестируемость и предсказуемое состояние.
Риски: Высокий порог входа (2–3 месяца обучения) и возможные проблемы с производительностью.
Как выбрать свою архитектуру?
- Стартап / MVP (1–3 devs): SwiftUI + простой MVVM. Приоритет на скорость.
- Среднее приложение (4–8 devs): MVVM + Coordinator + Dependency Injection.
- Enterprise (10+ devs): Clean Architecture или модульный MVVM. Приоритет на масштабируемость.
- А лучше: проанализировать свои задачи и проблемы, и выбрать архитектуру, которая будет решать именно их.
Какие выводы можно сделать?
- Главный архитектурный антипаттерн: Использовать «энтерпрайз» решения для проблем стартапа.
- Когда менять архитектуру: Только если текущая система «взорвется» в ближайшие 3 месяца. Если она продержится еще 2 года, рефакторинг не в приоритете.
- Важнее архитектуры: Чистота кода, регулярное ревью и тесты.
Важно помнить, что помимо парадигмальной смены архитектуры, есть много способов улучшить кодовую базу. Repository, Coordinator и DI можно внедрить независимо от выбора архитектуры. Да и сам выбор архитектуры не будет гарантировать успех потому, что хорошо приготовленный MVC лучше недожаренного Clean Architecture.
📎 The Architecture You’re Implementing Isn’t the Right One (And That’s Okay)
#D #Arch #Holywar
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7💯2
Интеграция сторонней библиотеки часто кажется спасением: 10 минут вместо нескольких спринтов самостоятельной разработки. Но за этим стоят множественные скрытые риски. Разработчики часто идут на это из-за жёстких дедлайнов, сложности задачи или давления бизнеса и не всегда задумываются о долгосрочных последствиях
🔺 Новые неожиданные баги с обновлениями версии Xcode или версии языка
🔺 Неопределенность с поддержкой - библиотеку запросто могут забросить и вы останетесь 1 на 1 с ней, формируя техдолг
Помимо обозначенных рисков есть еще и другие неудобства:
🔺 Сложности с "выпиливанием" библиотеки (опыт Dodo с Realm)
🔺 Увеличение размера бинарника
🔺 Ожидания стабильного релиза после очередных "подарков" от Apple
🔺 Конфликты с другими зависимостями
🔺 Сложность отладки - не видно stack trace в исходниках библиотеки
Нужен компромисс. В нашей практике необходимость сторонней зависимости оценивается на публичных техзащитах, в рамках которых разработчики анализируют новые фичи и пользовательские пути. Наши требования к самой библиотеке и ее интеграции, если будет доказана её важность, звучат так:
1️⃣ Необходимо владеть критическими частями кода, основной логикой, не отдавать флоу в "чужие руки"
2️⃣ Влияние зависимости на размер и скорость приложения должно быть контролируемым
3️⃣ Maintainers - надежные и проверенных сообществом, "живость" репозитория
4️⃣ Обращаем внимание на лицензию. Если зависимость критически важна и у нас недостаточно ресурса на разработку своего решения, то крайне желательно иметь возможность "форкнуть" и "причесать" под свои нужды в будущем в рамках техдолга
💎 Вместо итогов
Мне понравилась цитата из свежей статьи на Medium:
Если ты не контролируешь код, тогда код контролирует тебя
Имхо, со сторонними зависимостями это справедливо вдвойне, тк даже не вы написали этот код и зачастую вы его даже не видите в отладке
Думайте критически, подходите к проекту осознанно и не отпускайте все на автопилот 💫
#iOS #SoftwareArchitecture #Dependencies #TechDebt
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤3 2
Попытка сделать быстрые инкрементальные билды для AI, рядом с xcodebuild.
Как это работает:
xcodemake сначала прогоняет обычный xcodebuild, анализирует его и генерирует Makefile.
Дальше при повторных сборках компилируется только изменённый код (без ресурсов и ассетов).
За счёт этого повторные билды могут быть заметно быстрее.
Важно понимать ограничения:
- это экспериментальная фича
- инкрементальность касается только кода, любые изменения ресурсов, настроек проекта и т.п. легко приводят к необходимости возврата к xcodebuild
- магии уровня Bazel тут нет, это скорее аккуратный хак поверх существующих инструментов
Сам XcodeBuildMCP — это MCP-сервер, который даёт AI доступ к Xcode: сборки, схемы, симуляторы, девайсы, discovery-проекта и т.д.
Есть конфигурация: можно включать/выключать инкрементальные билды, ограничивать доступные workflow, настраивать поведение MCP под себя.
Вывод простой: пощупать можно, особенно если болит время локальных билдов, но тащить в прод-процессы — аккуратно и с холодной головой.
#L #AI #xcodebuild
Please open Telegram to view this post
VIEW IN TELEGRAM
@samwize
Incremental iOS Builds with Claude Code and XcodeBuildMCP
When using Claude Code for iOS development, raw xcodebuild commands are slow. While xcodebuild does support incremental builds, it’s not optimized for speed.
❤2 2
Казалось бы, тема пройдена вдоль и поперек, однако на технических интервью я периодически встречаю недопонимание принципов работы ARC даже у опытных разработчиков
⚡️Самый важный момент:
ARC "живет" только при компиляции
Он не отслеживает объекты в рантайме, не решает, когда освобождать память. Его задача - вставить в скомпилированный код вызовы функций, которые при MRC в Objective-C разработчик расставляет самостоятельно:
👉 objc_retain(ptr) - увеличивает счетчик ссылок объекта
👉 objc_release(ptr) - уменьшает счетчик
👉 objc_autorelease(ptr) - отложенное уменьшение счетчика, сегодня редкий кейс, об этом чуть ниже
Роль рантайма же - слепое исполнение инструкций. Если счётчик достигает нуля, объект немедленно деаллоцируется: вызывается deinit, освобождаются stored-свойства, память возвращается в кучу.
Что до счётчика ссылок - он хранится в заголовке объекта в куче и создаётся при аллокации объекта. Из Swift-кода доступа туда не получить
Используется редко, но стоит упомянуть в контексте autoreleasepool. ARC вставляет autorelease только тогда, когда на этапе компиляции не может точно определить момент окончания владения объектом:
👉 Границы Swift ↔ Objective-C
👉 Объекты с атрибутом
@autorelease
Важный момент: autorelease не откладывает деаллокацию. Он откладывает выполнение release в конце блока autoreleasepool, итерации runloop'а или при завершении потока
Именно поэтому autoreleasepool внутри циклов так важен для управления памятью. Без него множество больших объектов будут накапливаться в пуле до конца итерации runloop'а, вызывая скачок потребления памяти
Итоговая модель выглядит так:
1️⃣ Swift-код
2️⃣ ARC на этапе компиляции вставляет вызовы retain/release/autorelease
3️⃣ Рантайм аллоцирует объект с заголовком
4️⃣ Retain → увеличивает счётчик. Autorelease → добавляет объект в пул (счётчик не меняется)
5️⃣ Пул завешается → выполняются release для всех объектов в пуле
6️⃣ Если счётчик == 0 → немедленная деаллокация.
💫 Надеюсь, сегодня мне удалось повысить понимание этого процесса: что решает компилятор, что слепо исполняет рантайм и где ответственность переходит к разработчику
📎 Что почитать?
Постарше
Посвежее
Очень старая дока по ObjC, но многое актуально и для Swift
#iOS #Swift #ARC #MemoryManagement #Performance
Please open Telegram to view this post
VIEW IN TELEGRAM
Medium
Understanding Autorelease Pool in Swift for iOS Development
What is an Autorelease Pool?
❤5🔥3 2 1
SemVer — это не просто набор чисел, а коммуникационный инструмент, который помогает команде, QA, бекенду и поддержке быстро понять, что произошло в конкретном релизе.
Основная форма выглядит как:
MAJOR.MINOR.PATCH
Где:
MAJOR — большие изменения или breaking changes.
MINOR — новые функции без нарушения совместимости.
PATCH — исправления багов и мелкие улучшения.
Кроме базовых чисел семантика спецификации позволяет использовать метаданные через + и - например:
1.2.3+build45Метаданные могут включать:
- номер пайплайна сборки
- тип сборки (например, QA, backend, экспериментальный билд)
- любые служебные данные, которые важны для внутренней идентификации
Такие метки снимают массу вопросов при диагностике проблем и автоматически улучшают трассируемость между клиентом и бекендом.
Полезные эффекты от SemVer:
- Чёткое понимание, что изменилось (баг-фикс vs новая функция vs breaking change).
- Упрощённое взаимодействие между командами.
- Возможность строить логику QA/релизов на основе версии (alpha, beta, rc, build-meta).
- Меньше вопросов у поддержки и аналитиков при разборе инцидентов.
Вывод: если вы ещё не используете SemVer + метаданные в своих мобильных релизах — это однозначно стоит внедрить.
#L #semver
Please open Telegram to view this post
VIEW IN TELEGRAM
И начать год хочется с первой статьи — и снова про AI-кодинг.
Похоже, ничего не предвещает, что темой года станет что-то другое.
И, честно говоря, она хорошо резонирует с моим личным опытом за последний год.
В статье описывается опыт разработчика, который всецело использует AI-инструменты в ежедневной работе и заметно изменил за их счёт и стиль, и темпы разработки.
Пару мыслей, о которых мы уже не раз писали, но которые за этот год только усилились:
Модели стали слишком умными, чтобы жить по старым правилам.
Куча документации, отдельный промт-инжиниринг — всё это постепенно уходит.
В большинстве случаев ты просто просишь сделать то, что нужно, и модель делает.
Единственный нюанс: в новых проектах всё по-прежнему сильно выигрывает, если правильно дать старт архитектуре и сразу же вместе с AI сформулировать Agents.md.
Инструментов становится всё больше, и выбор должен идти от задачи.
Но если честно — OpenAI и Codex сейчас топ из топов.
Почти все исследования сходятся в одном: GPT-5.2 — имба.
Использование топовых LLM вместо локальной инфры неимоверно бустит качество.
Да, возможно, со временем баланс сместится.
Но точно не в этом году. Имхо.
P.S. Моё текущее комбо для кодинга:
xcodebuild MCP + Agents.md + Codex + VS Code — лучшее, что сейчас есть для написания кода.
Ограничения контекста, к сожалению, всё ещё боль для Codex - нет поддержки .ignore файла аля .claudeignore.
Думаю, все таки, в этом году мы должный прийти к единому .aiignore.
Очень жду, что в 2026 Codex подтянут именно эту часть.
#L #AI #MCP #iOS
Please open Telegram to view this post
VIEW IN TELEGRAM
Medium
The State of Agentic iOS Engineering in 2026
My perspective on AI-driven programming, workflows, and tooling
Если вы используете Codex в VS Code, важно осознанно управлять тем, какой контекст он видит. Особенно если в проекте есть секреты.
Если секреты нужно спрятать от Codex, есть несколько рабочих вариантов:
1. Ограничить контекст через workspace.
Настройте исключения в:
• .vscode/settings.json, или
• .code-workspace (лучше, если вы храните его в репозитории)
✅ Исключайте папки с секретами через files.exclude и search.exclude.
Это снижает вероятность того, что файлы попадут в индекс и контекст Codex.
2. Вообще не хранить секреты в репозитории
Лучший вариант с точки зрения безопасности:
• secrets вне repo,
• .env вне workspace,
• CI/CD variables или secret manager.
Это защищает не только от Codex, но и от любых IDE-расширений и автоматизаций.
Дополнительные базовые рекомендации:
• открывайте в VS Code только нужные модули проекта, а не корень монорепы;
• не открывайте файлы с секретами вручную;
• ограничьте сетевой доступ в настройках Codex;
• используйте sandbox / manual approval для действий агента.
Официальная документация по безопасности Codex
#L #AI #Security #Codex #VSCode
Please open Telegram to view this post
VIEW IN TELEGRAM
Openai
Security
How to securely operate and manage Codex agents
🔥3 1
В долгоживущих проектах часто возникают проблемы с инструментами и архитектурами. Они имеют свойство накапливаться и перемешиваться. Старый код где-то на completion handlers, где-то на Promises, в старых вьюмоделях используется RxSwift, в относительно новых используется Combine, совсем новый код пишется на Async/Await.
В результате мы имеем проект, который сложно читать, сложно дебажить, выше когнитивная нагрузка, больше технического долга. Конечно же, проблема кроется не в самих инструментах, а в отсутствии единого подхода к подбору инструмента под задачу.
В какой-то момент мы решили отказаться от зависимости на RxSwift и начали использовать Combine, а замыкания и промисы потихоньку стали переводить на Async/Await. Кажется, здесь все однозначно и понятно. Но что же выбрать между Async/Await и Combine?
Чем они отличаются концептуально?
🔹Async/Await это языковая модель структурированной конкуренции, встроенная в Swift. Она позволяет писать асинхронный код в линейном, последовательном стиле, максимально близком к синхронному.
- Структурированная конкуренция.
- Последовательный, линейный код.
- Легко читать как синхронный.
- Отлично ложится на модель «запрос → ответ».
Не сахар над completion handlers, а другая модель мышления, ориентированная на понятный контроль потока выполнения.
🔸Combine это фреймворк для реактивного программирования. Работа происходит не с одиночными результатами, а с потоками значений во времени.
- Реактивная парадигма.
- Работа с потоками значений во времени.
- Композиция, chaining, операторы (map, flatMap, retry, combineLatest).
- Подходит, когда данные изменяются непрерывно.
Не просто асинхронность, а реактивная архитектура.
Как осуществляется обработка ошибок и отмена задач?
🔹В Async/Await ошибки пробрасываются через throw, отмена через Task, поведение более очевидное.
🔸В Combine ошибки это часть stream’а, отмена через Cancellable, логика рассредоточена по цепочке операторов.
Почему нетворкинг это особый случай?
Большинство сетевых операций по своей природе не реактивны:
- один HTTP-запрос;
- один ответ;
- декодирование данных;
- возврат результата или ошибки.
🔹Async/await в этом контексте короче, проще, легче тестируется, проще обрабатывает ошибки через try/catch. Для сетевого слоя это даёт async/await преимущество в предсказуемости и прозрачности логики.
🔸Для такого сценария Combine часто избыточен, добавляет ненужную сложность, ухудшает читаемость.
С другой стороны Combine будет правильным выбором, если есть:
- WebSocket;
- live-updates;
- continuous streams данных;
- сложные зависимости между несколькими источниками данных;
- когда UI напрямую подписывается на поток изменений.
То есть там, где данные живут во времени, а не приходят один раз.
Какие выводы можно сделать?
Плохая идея использовать Combine и Async/Await вперемешку в одном сетевом слое. Лучше выбрать одну модель асинхронности для нетворкинга, чаще всего это будет Async/Await. Сombine стоит использовать выше по стеку (например, во ViewModel), если он нужен для реактивного UI.
Combine и Async/Await не конкуренты, а инструменты для разных задач.
📎 Combine vs Async/Await: Choosing the Right Concurrency Model for Networking
#D #Swift #Concurrency #Async #Combine
Please open Telegram to view this post
VIEW IN TELEGRAM
Medium
Combine vs Async/Await: Choosing the Right Concurrency Model for Networking
Your iOS networking is stuck between two worlds. Learn when to use Combine’s reactive streams vs Async/Await’s structured concurrency —…
❤4 3🔥2
Поэтому буду по-тихоньку "доставать из загашника".
Автор в статье пытается сделать кэш.
Ну не столько кеш, сколько упрощённую модель мира, в которой механизмы доступные из коробки начинают работать.
Он берёт iOS-сборку и насильно приводит её к детерминированному виду:
1. генерирует umbrella SPM-пакет как единый build graph
2. приводит DerivedData к стабильным абсолютным путям
3. поверх этого строит свой slot-based кеш.
После этого артефакты сборки «вдруг» становится переносимым: их можно zip-нуть и перекинуть между CI-раннерами, потому что внутри больше нет отличий в путях и случайных хешей.
Но важно:
- это не распределённый билд-кеш и не интеграция с Xcode.
- это локальный кеш, который можно копировать, потому что автор сначала нормализовал весь проект.
С инженерной точки зрения — решение тяжёлое и хрупкое.Это не то, что хочется тащить в прод.
Зато как упражнение для насмотренности — отличное, имхо, конечно.
Статья очень наглядно показывает, проблемы о которых мы уже общались ранее в разрезе tuist-а, из-за чего сложно сделать норм-кэш из коробки в iOS.
P.S.: Напоминание. Xcode 26 compilation cache делает лучше, но не идеально. Все еще ждем "красоты" из коробки.
#L #BuildCache #iOS #Tuist #xcode
Please open Telegram to view this post
VIEW IN TELEGRAM
Jeffverkoeyen
10× faster Xcode CI builds with slot caching — featherless software design
❤4🔥2
Еще одна статья про сравнение инструментов распараллеливания работы. Каждый инструмент решает свою задачу (последовательные операции, реактивные потоки, и защита общего состояния соответственно), как их сочетать и какие типичные ошибки нужно избегать при проектировании реального iOS-приложения.
Combine
Фреймворк для реактивных потоков: публикация значений во времени, операторы трансформации (map, filter, debounce, flatMap, merge и т.д.). Идеален для live-streams (поиск с debounce, данные с датчиков, пользовательский ввод, непрерывные обновления).
Async/await
Предназначен для последовательных, линейных асинхронных задач (одиночные сетевые запросы, цепочки запрос >> обработка >> рендер). Читабельный код, простой поток обработки ошибок и отмены задач через try/await и throws.
Actors
Механизм изоляции состояния: гарантирует последовательный доступ к свойствам актора, устраняя гонки данных и необходимость ручных блокировок. MainActor используется для UI-связанного состояния.
Есть ли паттерн выбора решения?
- Если это одна асинхронная операция, то используем async/await.
- Если это поток событий, то используем Combine.
- Если есть разделяемое изменяемое состояние, к которому обращаются несколько задач, то используем actors.
- Часто правильный вариантом будет комбинация: actor для хранения/защиты состояния, async/await для одиночных операций, Combine для подписки на потоки и реактивной логики.
Какие могут быть ошибки в использовании?
- Бессистемное смешивание Combine и async/await. Их совместное использование возможно, но лишние преобразования Publisher-AsyncSequence увеличивают сложность кода и накладные расходы.
- Использование actors повсюду. Акторы дают безопасность, но имеют затраты на изоляцию. Не нужно превращать в actor каждый класс, только те в которых есть общее изменяемое состояние.
- Игнорирование структурированной конкуренции. Вместо самостоятельного управления потоками лучше пользоваться TaskGroup/withTaskGroup для безопасного параллелизма.
Какие выводы можно сделать?
Swift Concurrency не обязует выбирать одну технологию: async/await, Combine и actors дополняют друг друга.
Правильный выбор инструмента повышает читаемость, производительность и безопасность приложения, а неправильный может свести преимущества к нулю.
📎 Mastering Swift Concurrency: When to Use Async/Await vs Combine vs Actors
#D #Swift #Concurrency #Async #Combine
Please open Telegram to view this post
VIEW IN TELEGRAM
Medium
Mastering Swift Concurrency: When to Use Async/Await vs Combine vs Actors
Navigate through Swift’s three concurrency models and create faster and more safe iOS applications that do not freeze your UI.
🔥4💯3
Не плохая статья про то, как на самом деле работают Universal Links в iOS — не на уровне «добавь AASA и всё заведётся», а на уровне Apple CDN, кешей и деплоя.
Внутри:
- как iOS получает и кеширует apple-app-site-association через CDN Apple
- почему обновления AASA могут “не приезжать” часами и что с этим делать
- как валидировать, что именно сейчас видит Apple
- какие есть стратегии безопасного деплоя изменений
Из моего опыта Universal Links — одна из самых мифологизированных частей iOS (для обывателей):
«почему не открывается», «почему открылось в Safari», «почему у одного работает, у другого нет».
Эта статья как раз закрывает эти “магические” зоны и объясняет механику.
Единственное, чего не хватает для полной картины — это тонкостей iOS-части, например:
- невозможности / костыльности передачи данных через Universal Link при перходе в приложение после установки из App Store
- различий поведения cold start / warm start / reinstall
Но как разбор инфраструктурной стороны (AASA, CDN, валидация, деплой) - кайф.
#L #UniversalLinks
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6💯3 3
Решил начать с темы несложной, но полезной.
Про Xcode File Templates большинство давно знает и использует, но статья натолкнула на мысль еще раз подсветить этот инструмент и напомнить, почему он действительно полезен в повседневной разработке.
✏️ Когда вы создаёте новый экран или фичу, почти всегда повторяется одно и то же:
- импорты
- базовая структура View
- ViewModel/Reducer
- Preview
- тестовый файл где-то рядом
Чаще всего это решается копипастом. Работает, но:
- легко забыть что-то переименовать
- появляются мелкие расхождения в стиле
- растёт количество рутинных действий
📝 Как раз в этом случае и можно использовать File Template. Это пользовательский шаблон файлов, который появляется прямо в Xcode.
Вы заранее описываете:
- какие файлы создаются
- какой в них код
- какие значения Xcode подставляет автоматически
А дальше Xcode сам создает нужные файлы.
🔸Из чего состоит шаблон:
- один или несколько
.swift файлов-
TemplateInfo.plist- плейсхолдеры в коде
Например:
___FILEBASENAME___
_FILEBASENAMEASIDENTIFIER_
При создании файла Xcode автоматически подставляет нужные значения.
🔹 Как создать файл из шаблона:
1. File → New → File…
2. Выбрать нужную категорию
3. Выбрать шаблон
4. Ввести имя
5. Получить готовые файлы в проекте
Без копипаста и лишних шагов.
🔍
TemplateInfo.plist описывает поведение шаблона:- имя шаблона, которое вы видите в Xcode
- описание
- тип шаблона
- список файлов, которые будут созданы
Через него можно:
- создавать сразу несколько файлов
- указать, какие файлы открывать после генерации
- управлять отображением шаблона в Xcode
По сути, именно
TemplateInfo.plist определяет, насколько шаблон будет удобен в реальной работе.✔️ Где шаблоны особенно хорошо работают:
- SwiftUI View + ViewModel
- Feature (View + Reducer + Preview)
- экраны дизайн-системы
- сетевые запросы с DTO
- тестовые файлы с общей структурой
Особенно полезно, когда:
- в проекте есть устоявшаяся архитектура
- важно соблюдать единый стиль
- в команду приходят новые разработчики
🍕 Почему полезно использовать шаблоны:
- меньше рутинных действий
- меньше ошибок от копипаста
- единая структура по проекту
- проще поддерживать кодовую базу
- быстрее старт новых фич
Но при регулярном использовании он заметно упрощает повседневную работу и помогает поддерживать аккуратную и предсказуемую структуру проекта.
#R #Xcode #Templates
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Mise приносит апгрейды в повседневную работу с окружением.
- убирает кучу неудобств, которые есть при ручной работе с brew, версиями SDK, средами и т.п.;
- устраняет необходимость поддерживать несколько инструментов вроде rbenv, pyenv, nodenv и т.д.;
- делает настройку окружения предсказуемой и декларативной.
Впервые я всерьёз посмотрел на mise в контексте работы с Tuist — и понял, что это реально прикольная вещь для стабильного dev-env.
У нас в iOS-проекте это уже работает так:
📌 bootstrap — главный sh скрипт для поднятия окружения проекта (mise, CocoaPods, Tuist, прочие зависимости)
📌 Ansible скрипты — для общей настройки рабочей машины (macos, settings, ssh, xcode, dev-tools и т.п.)
Такой дуэт даёт:
✅ универсальность на всех машинах команды и на CI
✅ быстрое приведение к рабочему состоянию
✅ минимум “у меня работает, а у тебя нет”
Если ещё не пробовали — настоятельно рекомендую погрузиться. Mise явно стоит внимания как альтернатива плурал-инструментам управления версиями и окружением.
#L #mise #Dev #CI
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4💯3
На этот раз про
Equatable и Comparable.Вещи знакомые, но на практике ими часто пользуются по инерции, не всегда задумываясь, чем они отличаются.
🔹
Equatable отвечает ровно на один вопрос:равны ли два значения между собой.
struct User: Equatable {
let id: Int
let name: String
}Теперь можно:
• сравнивать
user1 == user2• использовать
removeDuplicates()• помогать SwiftUI понимать, изменилось ли состояние
Где это обычно нужно:
• модели данных
• state в SwiftUI
• тесты
Важно:
Equatable ничего не говорит про порядок. Только одинаковые значения или нет.🔹
Comparable нужен тогда, когда элементы можно упорядочить.struct Score: Comparable {
let value: Int
static func < (lhs: Score, rhs: Score) -> Bool {
lhs.value < rhs.value
}
}После этого можно:
• сортировать массивы
• использовать
min() и max()• работать с диапазонами
scores.sorted()
scores.max()
Важный момент:
если тип
Comparable, он автоматически обязан быть Equatable.Если мы умеем сравнивать порядок, мы обязаны понимать равенство.
🔹 В проектах нередко встречается:
•
Comparable, хотя сортировка нигде не используется• сложная логика сравнения «на будущее»
• протоколы, добавленные просто на всякий случай
На практике это редко даёт пользу и чаще усложняет модель.
Equatable и Comparable решают разные задачи, и в большинстве случаев достаточно минимально необходимого протокола.Иногда полезно просто спросить себя:
я хочу проверить равенство или действительно упорядочить данные?
Ответ на этот вопрос часто делает модель и код вокруг неё заметно проще.
#R #Swift #SwiftUI
Please open Telegram to view this post
VIEW IN TELEGRAM
Листал свой фид, искал вдохновение о чем бы написать в канал и нашелся, на первый взгляд, идеальный кандидат на первый пост в этом году от меня
О чем: Swift заменил Objective-C не потому, что тот был стар, а потому, что
developers were the bottleneck
🎯Какие тейки:
• разработка была секретна
• в iOS 15.1 16 из 22 фиксов были связаны с управлением памятью = дорого для Apple (из-за регуляторных затрат)
• в целом ошибки при работе с памятью стоили Apple $67 ярдов
• последние фичи в Obj-C были как раз для совместимости с Swift
🚀В Swift Apple сняла значительную часть рисков с разработчиков (на самом деле с себя) и переложила на компилятор:
• Снесла (почти) Message dispatch = меньше проверок в runtime
• В целом система типов стала жестче
• В Swift Concurrency отдали компилятору разгребать Data Races = убрали самый сложный тип багов
• Синтаксис приведен ближе к модным Python/JS и тд = больше вкатунов
В целом, история звучит складно, но
• откуда тейк про 67 ярдов - не понятно,
• не припомню, чтобы по статистике от OWASP мобилки сильно страдали от memory management, как будто в топе были иные проблемы (можно вспомнить про Dirty-COW, но насколько она эксплуатируема в мобилках - инфы нет)
• раз была серьезная проблема, то почему так мало персонала было привлечено к разработке и релиз состоялся только через 4 года? "Небизнесовый" подход какой-то, тот же Go за год-два сварили (чую "это другое", спорить не буду)
ну и добило меня
Java had solved memory safety with garbage collection — but the unpredictable pauses were unacceptable for iOS’s fluid 60fps animations
как будто у дроид-коллег были большие проблемы с 60fps анимациями именно из-за сборщика мусора, напишите в комменты
По итогу ощущение такое... то-ли кликбейт, то-ли нейронка написала (длинных "—" много, да, это косвенно), грустно
А вот выводы автор делает как будто в отрыве от всей остальной статьи, они довольно универсальные
👉 Кооперируйтесь с компилятором - переложите на него больше работы, уменьшив число проверок в runtime
👉 Подходите к коду осознанно
👉 Код должен быть максимально явным, не допускайте двусмысленности
👉 Используйте систему типов для описания бизнес логики (отсылка на Domain Driven Design - там это важная часть)
и от себя
⚡️Думайте критически, в эпоху нейронок важно фильтровать
#M #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
Medium
Swift Wasn’t Created to Replace Objective-C. It Was Created to Replace You.
The uncomfortable truth about why Apple spent 4 years building a language in secret — and what it means for your career
🔥5 3💩2
Модульность это разделение кодовой базы на четко очерченные, изолированные единицы с явными границами ответственности.
Каждый модуль имеет публичный интерфейс, скрывает внутреннюю реализацию и может эволюционировать независимо.
Модульность нужна не всегда. Для небольших проектов и прототипов она часто создает лишние накладные расходы. В этом случае простота и скорость может быть важнее архитектурной чистоты.
Но когда продукт стабилизируется и становится ясно, что кодовая база будет расти, модульность помогает управлять сложностью, задает границы владения кодом и предотвращает деградацию в тесно связанный монолит.
Проектирование структуры до написания кода
Архитектуру стоит продумывать до начала реализации, а не по ходу роста проекта.
Простая диаграмма модулей помогает определить границы, проясняет зависимости, снижает количество реактивных решений позже.
Начинать рекомендуется с базового слоя: общие модели данных, сетевой слой, фундаментальные сущности. Раннее формирование этого слоя снижает риск болезненных переделок в будущем.
Три основные категории модулей
🛠️ Foundation-модули содержат общие модели, примитивы, инфраструктурные компоненты. Они не зависят ни от чего выше по иерархии и используются практически везде. Также они не должны содержать пользовательские сценарии.
🧰 Service-модули содержат переиспользуемую логику и сервисы. Они зависят от Foundation и используются фичами. Foundation-модули никогда не должны зависеть от Service-модулей, это нарушает иерархию.
🚚 Feature-модули содержат пользовательские сценарии (онбординг, оплата, профиль и т. д.). Они могут зависеть от Foundation и Services, но не должны зависеть друг от друга. Горизонтальные связи между фичами быстро разрушают архитектуру и возвращают монолитные проблемы.
Модульность ради модульности
Внедрение модульности как модного веяния без должного проектирования ведет к проблемам при которых возникают циклы зависимостей, универсальные сервисы, раздутые публичные API. В долгосрочной перспективе растет технический долг, а кодовую базу становится поддерживать труднее чем монолит.
Хотя определенные плюсы все равно будут присутствовать. Будет меньше конфликтов на мержах и ускорится параллельная разработка.
📎 Modularity as an Architectural Choice
#D #Arch #Modularity #Clean
Please open Telegram to view this post
VIEW IN TELEGRAM
Livsy Code → Learn Swift the smart way
Modularity as an Architectural Choice → Livsy Code
Greetings, traveler! Modularity is an architectural approach where a codebase is split into well-defined, independent units with explicit responsibilities and boundaries. Each module exposes a clear public interface and hides its internal details, allowing…
🔥4 4❤2
У каждого модуля должен быть явно определен контракт:
🛠️ В Foundation-модулях допустим широкий API, но изменения будут дороже.
🧰 В Service-модулях API должен быть узким и сфокусированным, его рост является сигнал о "божественной" ответственности.
🚚 В Feature-модулях должен быть минимальный интерфейс: точка входа и результат выполнения сценария.
Навигация и взаимодействие между фичами
Внутренняя навигация это ответственность самой фичи. Переходы между фичами не должны происходить напрямую. Часто они выносятся во внешний координатор (AppCoordinator, TabCoordinator и т. д.).
Фича сигнализирует о завершении сценария, а координатор решает куда идти дальше и передает данные следующей фиче. Это сохраняет изоляцию и прозрачность зависимостей.
Сборка фич и обмен данными
Координатор не должен собирать внутренности фичи. Каждая фича сама знает, какие зависимости ей нужны и предоставляет assembly API (factory, builder и т.п). Обмен данными происходит через result-модели, а при наличии общих моделей, они выносятся в отдельный нейтральный модуль.
Для сложного взаимодействия возможен mediator-модуль, который знает о нескольких фичах, управляет их взаимодействием. Такой подход используется реже из-за архитектурной сложности.
Протокольные bridge-модули
Bridge-модули на протоколах выглядят красиво с точки зрения чистой архитектуры, но увеличивают количество модулей, время сборки и когнитивную нагрузку. Часто они создают иллюзию слабой связанности.
Они оправданы в конкретных случаях где требуется изоляция тяжелых зависимостей, тестирование или постепенный переход от монолита. Внутри фич протоколы допустимы, но стоит иметь во внимании, что гипергибкость почти никогда не окупается.
Какие выводы можно сделать?
Модульность это не слепой рефакторинг, а осознанная архитектурная практика, которая снижает сложность, улучшает масштабируемость команды, повышает предсказуемость разработки, а также позволяет превращать код в долгосрочные активы.
Инструменты могут помочь, но не заменяют архитектурное мышление, дисциплину и понимание границ ответственности. Без этого модульная система быстро скатывается в более замаскированный хаос.
📎 Modularity as an Architectural Choice
#D #Arch #Modularity #Clean
Please open Telegram to view this post
VIEW IN TELEGRAM
Livsy Code → Learn Swift the smart way
Modularity as an Architectural Choice → Livsy Code
Greetings, traveler! Modularity is an architectural approach where a codebase is split into well-defined, independent units with explicit responsibilities and boundaries. Each module exposes a clear public interface and hides its internal details, allowing…
❤3🔥2 2
В iOS есть два системных механизма от Apple, которые реально помогают с анти-фродом — DeviceCheck и App Attest.
Оба — клиентские фреймворки. Они работают на устройстве и генерируют криптографические доказательства.
Сервер сам ничего «не проверяет» — он просто отправляет эти данные в Apple и уже по ответу решает, что делать дальше.
📱 DeviceCheck
Позволяет понять, что запрос пришёл с реального устройства и пользователь не пытается подделать свою активность.
- Выпускаем ключ для приложения на developer.apple.com
- Клиент в рантайме получает deviceToken через DeviceCheck API
- Сервер валидирует его через Apple и может читать/писать два бита состояния, которые Apple хранит для пары устройство + приложение (подписывая с помощью jwt).
Типичные кейсы:
- «один бонус на устройство»
- пометить девайс как подозрительный
- soft-ban без аккаунта
🔐 App Attest
Решает другую задачу (аналогичную deprecated ручке v1/validate_device_token) — подтверждает, что запрос идёт от оригинального приложения, а не от модифицированного.
- Добавляется новый капабилити
- Получается ключ (создаётся внутри Secure Enclave, наружу не экспортируется) для генерации nonсe с бекенда
- Генерируется обьект attestation на основе приватного ключа и nonce и отправляется на бекенд для дальнейших проверок
- Далее с помощью приватного ключа и nonсe генерируются assertion для отправки на сервер и верификации приложения
Application даёт сигнал, Apple — источник доверия, Backend принимает бизнес-решение.
P.S.: Ну и как всегда в разрезе security - оговорки. Jailbreak - все сломает (улучшайте jailbreak-detection), SSL-pinning поможет повысить защиту, скрывайте секреты, используйте обфускацию и шифрование.
#L #Security #AntiFraud #DeviceCheck #iOS
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7
——————
В разработке нередко встречаются ситуации, когда разные части проекта имеют различный внешний вид и поведение, что затрудняет поддержку, ведет к увеличению сроков выпуска обновлений и ухудшению качества продукта.
Решением подобных проблем является дизайн‑система, которая обеспечивает единую библиотеку компонентов и строгие правила их использования, позволяя сократить время разработки, минимизировать расхождения между частями продукта и значительно облегчить дальнейшую работу над проектом.
Наш братик и по совместительству Android‑разработчик из СЗ, в статье рассказывает, как строили мобильную дизайн‑систему на iOS и Android проекте на SUI и Compose, соответственно, и оптимизировали интерфейсы
#L #DesignSystem #iOS #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
Хабр
Особенности построения и развития дизайн-системы в мобильном приложении СберЗдоровья
При разработке ИТ‑продуктов команды нередко сталкиваются с ситуацией, когда разные части проекта имеют различный внешний вид и поведение, что затрудняет поддержку, ведет...
🔥4 4❤2
Существует 3 типа линковки:
• Static
• Dynamic
• Mergeable
Почему это важно? Тип линковки напрямую влияет на:
• модульность и управляемость архитектуры,
• размер приложения,
• скорость запуска.
Хороший разбор с примерами — тут.
Отдельно отмечу mergeable libraries. Tuist прямо говорит о cost of convenience,
и я с этим полностью согласен:
➡️ mergeable почти всегда сложнее организовать,
➡️ сложнее явно контролировать и дебажить, чем осознанная и прозрачная логика линковки.
Подход который использую я, и который сквозь время доказал свою пригодность и масштабируемость (под бинарные кеши всякие т.д. не страдая качеством):
• staticForDeploy — все библиотеки статические, кроме тех, что шарятся с экстеншонами
• dynamicForDev — всё динамика для комфортной разработки
Вся логика механизма зашита в Tuist.ProjectDenoscriptionHelpers, дополняется оверрайдами в CocoaPods и SPM.
Итог: быстрее старт приложения в проде, удобство разработки и контролируемая архитектура без магии.
P.S.: Если интересно, чуть больше года назад рассказывал об этом подробнее.
#L #Linkage #iOS
Please open Telegram to view this post
VIEW IN TELEGRAM
Livsy Code → Learn Swift the smart way
Static, Dynamic, and Mergeable Linking in Modular iOS Apps → Livsy Code
Greetings, traveler! Modularization changes how a project feels day to day. The codebase becomes easier to reason about, feature work becomes more parallel, and dependency boundaries start to matter. At the same time, the build system becomes part of the…
🔥7