YDC — Pizza Powered iOS – Telegram
YDC — Pizza Powered iOS
242 subscribers
65 photos
95 links
Young Da Code 👨‍💻
Первый командный дайджест о мобильной разработке 🍕
Download Telegram
🤫 Секреты на клиенте: как снизить вероятность утечки с нуля до почти нуля

Мобильное приложение всегда оказывается на устройстве пользователя — а значит, потенциально доступ к нему может быть и у злоумышленника. Это значительно повышает требования к безопасности выпускаемых продуктов, поскольку в коде приложений неизбежно содержатся конфиденциальные данные, которые используются разработчиками. Соответственно, обязательным условием становится защита секретов на клиенте от утечек.

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

Материал подготовлен по мотивам доклада на Podlodka iOS Crew, посмотреть можно здесь


#L #CS #encryption #obfuscation

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
7
🤓 📣 Meta переманила главного дизайнера Apple!

Alan Dye - человек, представивший Liquid Glass на WWDC 2025 — уходит из Apple и переходит к Марку Цукербергу.
В Meta он займётся дизайном ИИ-гаджетов.
В Apple его заменит ветеран компании Steve Lemay.

#L #News

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
5🔥3
😄 Долгий путь Concurrency в Swift: Structured, Strict, Approachable

🔹Swift 4.0
В 2017 году был опубликован Swift Concurrency Manifesto. Это фундаментальный документ от Chris Lattner, в котором описано видение и архитектура будущей конкурентности в Swift. Именно в нем заложена база для всего, что мы сегодня называем Swift Concurrency, включая actors, async/await, structured concurrency, Sendable и strict concurrency.

🔹Swift 5.5
В 2021 году были добавлены ключевые строительные блоки — async/await, Task/TaskGroup, actor и базовые правила про Sendable/изоляцию. Эти элементы создали основу структурированного параллелизма, на которую позднее были надстроены более жёсткие проверки безопасности конкурентности. Apple Developer

🔹Swift 6.0
В 2024 году было оформлено само понятие и более строгое поведение Strict Concurrency (активная работа и переключение к более строгим проверкам в Swift 6 и связанных proposal'ах/обсуждениях). Apple даёт рекомендации по adopting strict concurrency для Swift 6 — то есть базу заложили в 5.5, а строгие проверки стали сопутствующей эволюцией в следующих версиях. Apple Developer

🔹Swift 6.2
В 2025 году смещается фокус на удобство и Approachable Concurrency. Это попытка сделать переход на async/await и строгую модель акторов более мягким и предсказуемым.

Подробнее про Approachable Concurrency

Approachable Concurrency это не просто концепт, это набор новых/изменённых языковых фич и флагов в Xcode/Swift, призванных сделать переход на async/await и строгую модель конкурентности менее болезненным.

Это про progressive disclosure: по умолчанию код остаётся ближе к однопоточному, а более строгие ограничения появляются только когда вы сознательно вводите параллельность.

Какие фичи включаются

В swiftSettings можно активировать новые поведения компилятора:

🔹DisableOutwardActorInference
Отключает «растекание» глобальных акторов наружу. Раньше Swift мог автоматически навязать, например, @MainActor всему типу из-за одного property wrapper. Теперь это нужно указывать явно. Меньше сюрпризов и скрытой изоляции.

🔹GlobalActorIsolatedTypesUsability
Упрощает взаимодействие с типами, изолированными глобальным актором. Компилятор становится менее строгим в местах, где раньше требовал лишних @Sendable или блокировал вызовы. Код становится чище, а изоляция более предсказуемой.

🔹InferIsolatedConformances
Позволяет Swift автоматически понимать, что реализация протокола тоже «изолирована» актором. Например, если ваш класс @MainActor, то его conformances больше не нужно вручную помечать актором и компилятор корректно справится сам.

🔹InferSendableFromCaptures
Компилятор начинает автоматически выводить @Sendable для функций и замыканий, если это безопасно. Меньше ручных пометок, меньше ошибок вида «closure is not Sendable», меньше boilerplate.

🔹NonisolatedNonsendingByDefault
Главное и потенциально ломающее изменение. Неизолированные async-функции больше не гарантируют выполнение на глобальном executor, они исполняются на акторе вызывающего. Если нужна реальная параллельность, функцию надо явно помечать @concurrent.

Почему это важно

Если просто включить всё в большом проекте, можно получить неожиданные изменения исполнения:

1. Функции могут начать работать на других акторах.
2. Появится больше варнингов.
3. Возможны скрытые гонки данных.

Как мигрировать безопасно

1. Включить настройки по одной, а не все сразу.
2. После каждого шага — тесты + Thread Sanitizer.
3. Проверить async-методы: если они должны быть параллельными, выставить @concurrent.
4. В Swift Package — обновить swift-tools-version до 6.2.

Что имеем в итоге

Approachable Concurrency делает Swift конкурентность понятнее и безопаснее, но требует аккуратной миграции. Это не просто новые аннотации. Это изменения в том, как Swift действительно будет выполняет код.

Включаем 6.2 в целом для таргетов и в том числе в пакетах.

📓 Approachable Concurrency in Swift 6.2: A Clear Guide
🎥 Swift 6.2: Finally - Concurrency Made Approachable

#D #Swift #Concurrency #Async

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
3
🇷🇺 В России «отрубают» FaceTime. По данным Роскомнадзор, сервис «используется для организации терактов и мошенничества» (как и многие другие мессенджеры и VPN).
🛑 Вместе с этим продолжают совершенствовать ограничения к VPN.
🤔 Кто уже начал использовать Max?

#L #sanctions #FaceTime #VPN

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
3
🤓 Когда ~10 лет назад я начинал в разработке на ASP.NET, на бэке мы много работали с БД и активно использовали Specification + Repository.

Это давало магическое ощущение:
типобезопасно, без строковых SQL-запросов, удобно фильтровать и получать данные.
Чтобы понять всю механику работы, я тогда потратил не один день на чтение документации и мучения ведущего разраба, но кайф от подхода был огромный.

Позже я пытался воспроизвести то же на Symfony + PHP, и почувствовал огромную разницу работы:
другие абстракции, ActiveRecord по всему проекту…
В итоге (менее типизированный) почти-голый SQL на PHP, как ни странно, работал кратно быстрее, чем ASP.NET со спецификациями.
На то было много причин, от местоположения арендованных серверов, до специфики работы паттернов и фильтрации, сейчас не об этом.

Когда я пришёл в мобилку, первый проект тоже был с БД, и я долго объяснял тимлиду, почему типобезопасный доступ к данным - топ.
На самом деле я просто хотел того же опыта, той же предсказуемости.

И вот теперь — появился #Predicate, который по сути является макросом над NSPredicate.
То есть всё те же плюсы типобезопасности + читабельности, но без существенного падения перформанса, по идее (посмотрим на практике).

В целом, макросы всё глубже прорастают в Swift-разработку — и, имхо, делают нашу жизнь сильно лучше.

#L #SwiftData #Predicate

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥422
🔄 SwiftUI: удобная прокрутка с помощью ScrollTargetBehavior

Почитал хорошую статью на Medium про механизм прокрутки в SwiftUI – ScrollTargetBehavior.
Решил поделиться самой полезной выжимкой + реальными примерами.

🧲 Что вообще такое “snap”?
Snap-прокрутка – это когда после скролла список «прилипает» к ближайшему элементу.
Не останавливается где попало, не обрезает карточку наполовину, а аккуратно доезжает до нужной позиции.

Примеры из жизни:
- карусель App Store
- галереи фото
- карточки в музыкальных приложениях

Раньше приходилось собирать на UIScrollViewDelegate, offset-вычислениях и тд.
Теперь – один модификатор.

🍕 Что даёт ScrollTargetBehavior
В SwiftUI есть два поведения «из коробки»:
- .paging
Постраничная прокрутка. Один свайп = один экран/элемент.
- .viewAligned
Выравнивание по ближайшему элементу – подходит для карточек и горизонтальных списков.

И самое интересное: можно написать своё собственное поведение.
Учитывать скорость свайпа, размеры элементов, направление – и решать, куда именно «приклеится» список.

👩‍💻 Примеры
1. Карусель изображений с paging
ScrollView(.horizontal) {
LazyHStack(spacing: 0) {
ForEach(items) { item in
CardView(item)
.frame(width: UIScreen.main.bounds.width)
}
}
.scrollTargetLayout()
}
.scrollTargetBehavior(.paging)
.scrollIndicators(.hidden)


Теперь листается как полноценная галерея – экран за экраном.

2. Вертикальный список, который «прилипает» к ближайшей карточке
ScrollView {
LazyVStack(spacing: 16) {
ForEach(cards) { card in
CardView(card)
.containerRelativeFrame(.vertical)
}
}
.scrollTargetLayout()
}
.scrollTargetBehavior(.viewAligned)


После прокрутки список автоматически выравнивается по ближайшему элементу.

3. Кастомный snap: быстрый свайп пролистываем на 2 карточки
struct FastPaging: ScrollTargetBehavior {
func updateTarget(_ target: inout ScrollTarget,
context: ScrollTargetBehaviorContext) {

// если жест быстрый — пролистываем дальше
if context.velocity.magnitude > 1500 {
target.index += context.velocity.width > 0 ? 2 : -2
} else {
// стандартная логика
target = context.target
}
}
}


Использование:
.scrollTargetBehavior(FastPaging())


🍕 Почему это лучше старых решений
До iOS 17 snap-прокрутку собирали через:
- вычисление scrollOffset
- DragGesture + кастомные вычисления позиции
- UIScrollViewDelegate через UIViewRepresentable

Теперь:
- поведение описано декларативно
- ScrollView сам учитывает инерцию и скорость жеста
- одинаково работает в LazyVStack / LazyHStack / обычном ScrollView
- можно расширять собственными правилами

🎯 Что получаем?
ScrollTargetBehavior – современный, нативный и гибкий способ управлять прокруткой в SwiftUI:
- аккуратный snap
- предсказуемое и понятное поведение
- возможность тонкой настройки
- минимум костылей, максимум стабильности

#R #SwiftUI

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
4🔥2
😋 🎮 Наткнулся на статью про реверс игры для Nintendo 64.
Автор декомпилирует Snowboard Kids 2 в режиме matching decompilation - когда итоговый C-код после компиляции должен давать тот же бинарь, что и оригинальный ассемблер.

🧠 Для работы он построил флоу с Claude-агентом:
1. Использует decomp.me для исходной декомпиляции.
2. Сравнивает результат компиляции восстановленного кода с оригинальным бинарём.
3. Если совпадение неполное - подключает агентов, которые ищут расхождения и итеративно повторяют цикл декомпиляция → компиляция → сравнение.
4. В случае стагнации или деградации агент передаёт задачу человеку.

Где агенты хороши:
— ловят повторяющиеся паттерны в машинном коде;
— предлагают варианты функций, которые вручную копать долго;
— ускоряют черновые этапы и снимают рутину.

Где они проваливаются:
— иногда ошибаются в базовой арифметике;
— «забывают» окружение (вплоть до выбранного компилятора);
— ломают control flow в ветвистых кусках в духе goto.

🔧 Вывод: как инструмент — 🔥.
Агенты реально ускоряют реверс и снимают тонны ручной боли.
Но полностью полагаться на ИИ нельзя: без человека это всё ещё красивая, но бесполезная поделка.

#L #AI #ReverseEngineering #Decompilation

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
33
🤓 💬 Рабочий кейс: правильная коммуникация в команде — половина успеха.

Навеяло мысли после одно рабочего кейса.
Из-за недопонимания, ребята сделали ненужную работу.
И потом еще потратили время на откатывание, которое, к слову, можно было не делать.
Если бы верно обсудили варианты решений.

Мои правила, комммуникации в чатах:

1️⃣ Пиши всё в одном сообщении.
Приветствие, контекст, что нужно, сроки — одним четким блоком. Это экономит время и снижает шанс быть неправильно понятым.

2️⃣ Собирай обратную связь.
Уточняй, верно ли тебя поняли. Сам реагируй тоже одним сообщением и — если возможно — в треде. Подзывай всех участников, чтобы никто не выпал.

3️⃣ Фиксируй решение.
Одним финальным сообщением: контекст → решение → почему так. Это сильно снижает количество “а что в итоге решили?”.

💡 Самое важное — пункты 1 и 3.

И да, имхо, зачастую, “правильная коммуникация” — это 50–80% успеха задачи.
Наблюдение: люди с хорошими коммуникативными навыками растут в карьере быстрее. 😉

P.S.: Почитать о коммуникации от коучей можно много всего, базово, эти 3 правила работают со мной с начала карьеры, после того как один мой руководитель, обьяснил их мне при очередной моей попытке достать его "до кишок" своими вопросами по задаче.

#L #Communication

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
6
🤓 🚀 Compile vs Runtime. Начало

Мы часто пишем код так, будто машинка за кадром просто «выполняет инструкции», но в реальности путь от исходника до выполнения куда длиннее и интереснее.
Сегодня попробуем пройти его последовательно: от compile time и LLVM IR до Swift runtime, Obj-C runtime и механизмов диспетчеризации методов.

🧩 Compile Time vs Runtime:
Swift — язык, который сознательно переносит максимум работы на этап компиляции.
Чем больше информации компилятор узнает о типах, generics, наследовании, тем меньше остаётся неопределённости в рантайме, и тем быстрее будет работать ваш код.

Compile Time — что делает компилятор Swift:
- проверяет типы и связи между ними
- анализирует возможности оптимизации
- генерирует LLVM IR — промежуточное представление программы
- формирует метаданные типов и служебные таблицы, необходимые рантайму
решает, можно ли:
- специализировать generics в конкретный код
- де-виртуализировать вызовы
- развернуть протокол в статический вызов
- Если типы известны заранее — компилятор построит прямой статический вызов без участия runtime.

Runtime — что происходит «вживую»:
- выделяется память под объекты
- работает ARC
- инициализируются метаданные типов
- происходит lookup таблиц: vtable, witness table
- выполняется упаковка/распаковка типов в existential container
- работает Obj-C runtime
- вызываются методы — статические, виртуальные или динамические
Compile time строит все дороги и развязки. Runtime по ним едет.


🟣 Obj-C Runtime — всё объект, всё сообщение:
Чтобы оценить, насколько иначе работает Swift, сначала вспомним принцип Obj-C.
Объект в Obj-C — это структура, в которой есть поле isa:

struct objc_object {
Class isa;
};

Классы в objc одновременно и классы и обьекты.

Вызов метода в objc:

[obj doSomething];

на самом деле является:
вызовом функции

objc_msgSend(obj, @selector(doSomething))

, которая:
- читает obj->isa
- ищет селектор в кеше
- поднимается по иерархии классов (если не находит метод — запускает цепочку message forwarding)
- и только после всех попыток бросает unrecognized selector
Да, Objective-C — это надстройка над языком C, которая добавляет к нему объектно-ориентированную парадигму (ООП) и динамические возможности через систему сообщений и объекты, сохраняя при этом полную совместимость с кодом на чистом C, что позволяет использовать их совместно


🔵 Swift Runtime — другой мир:
Swift не опирается на Obj-C runtime (кроме совместимого кода) и имеет собственную модель исполнения.
Swift-структуры и enum:
- xранятся inline (на стеке или внутри других структур)
- не имеют isa
- становятся heap-объектами только при боксинге

Swift-классы:
- всегда heap-объекты
- имеют header, содержащий указатель на Swift type metadata
- если совместимы с Obj-C — получают и поле isa

То есть:
У value types нет Obj-C-объектности. У reference types есть типовая информация, но она не идентична Obj-C-isa — Swift организует её иначе.

🧬 LLVM IR — слой, где принимаются ключевые решения:
Swift не компилируется напрямую в машинный код — сначала он становится LLVM IR.
Это низкоуровневое, но типобезопасное представление, в котором компилятор:
- специализует generics (когда возможно)
- удаляет виртуальность
- inline-ит функции
- оптимизирует вызовы протоколов
- устраняет лишние копирования
- уменьшает динамику

⚙️ Именно на IR-уровне решается, каким будет вызов метода:
Static dispatch
- метод у struct/enum/extension
- метод final
- функция свободная
- generics-функция после специализации
Witness dispatch
Вызов через протокол, когда тип известен, но вызов идёт «через протокол».
Компилятор кладёт указатели методов в witness table, и вызов выполняется через неё.
Virtual dispatch
Если метод может быть переопределён — он попадает в таблицу виртуальных методов.
Если нельзя — становится статическим вызовом.
Dynamic Dispatch (Obj-C) Когда Swift-код:
- наследует NSObject
- помечен @objc
- помечен dynamic
Вызов идёт через objc_msgSend.

📎 Swift Runtime

#L #SwiftRuntime #MetodDispatch

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
4💩22
😋 Swift Bits: @objc vs dynamic

Вчера мы говорили про compile и runtime.
Сейчас - поговорим про интероп с objc в Swift, и зачем нужны @objc и dynamic.

@objc
Делает символ «видимым» для Objective-C runtime.

Что даёт:
• присваивает selector
• для свойств getter и setter раскрываются в Objective-C методы:
• регистрирует классы в ObjC runtime: objc_addClass
• позволяет использовать swizzling, KVС/KVO
ObjC-код вызывает метод через message dispatch
Swift может игнорировать динамику и вызвать @objc-метод статически или через vtable.

@objc не заставляет Swift использовать objc_msgSend.

dynamic - "is what forces Objective-C–style message dispatch even from Swift".

#L #objc #runtime #swift #interop

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
42
🤪 Linux Foundation анонсировала Agentic AI Foundation
- новый нейтральный фонд для развития открытых стандартов и инструментов для агентных AI-систем.
В его стартовый пул вошли такие проекты, как Model Context Protocol (MCP) от Anthropic, AGENTS.md от OpenAI и фреймворк goose, а также поддержка крупных игроков (Google, Microsoft, AWS, Cloudflare и др.).
Цель инициативы - создать общие протоколы и экосистему для совместимых, открытых AI-агентов, избежать несовместимых проприетарных инструментов и ускорить развитие агентных решений под контролем сообщества разработчиков.

P.S.: На фоне анонса национальной программы - Genesis Mission (направленной на стратегическое ускорение национальных AI-исследований и инфраструктуры), такой шаг по открытым стандартам и сотрудничеству выглядит как "балансирующий шаг": развитие открытой, стандартизированной платформы может усилить экосистему и обеспечить более широкую совместимость инструментов, чем закрытые проприетарные подходы.

#L #AI

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
33
🤔 Вчера обсуждали с нашими хорошими друзьям и коллегами из Яндекса тему использования AI-кодеров и связанных с этим security-рисков (отсылка к их открытому рассказу на YouTube).

Позиция у коллег довольно прагматичная:
- Сам код без секретов коммерческой ценности почти не несет. Сегодня одна реализация, завтра другая.
- Чувствительность модулей зависит от домена. В банке понятно, что есть особо критичные части. В обычном e-commerce секретов немного: корзина, витрина, каталог.
- Всё заранее согласовано с безопасностью, получено официальное добро.
- Контекст кодера должен быть ограничен. Не всё и не из всей монорепы нужно отдавать в облачный embedding.

Подход абсолютно рабочий, но не универсальный. У проектов с другой спецификой бизнеса может быть куда более низкая толерантность к риску.
И важно помнить несколько принципов опеки над своим кодом:
- ограничивайте контекст AI-кодера
- используйте .cursorignore/.claudeignore
- держите только проверенные MCP и фильтруйте запросы от потенциальных prompt injection (мы писали про это тут).

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

AI-кодеры дают огромный прирост скорости, но требуют осознанного контурa безопасности. Важно понимать, что безопасно в вашем домене, а что нет, и какое количество контекста вы готовы доверить облаку.

#L #AI #Security

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
6🔥52
🤪 Swift Configuration 1.0 — появился стабильный, типобезопасный инструмент для работы с конфигурациями в Swift-проектах.

Теперь можно единообразно собирать конфиг из ENV, файлов, аргументов командной строки и своих провайдеров, без самописных прослоек и разрозненной логики. Это особенно ценно для CLI-утилит и серверных приложений.

Из ближних примеров: те же Tuist Env-ы вполне можно было бы реализовать на Swift Configuration нативнее, чем через кастомные решения.


let config = ConfigReader(providers: [
EnvironmentVariablesProvider(),
try await FileProvider<JSONSnapshot>(filePath: "config.json")
])

let apiURL = config.string(forKey: "api.url")


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

#L #SwiftConfiguration #Env

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥42
😋 Как работают xcodebuild, swift-build и Swift Build — разница и отношения внутри экосистемы Swift

В продолжение рассмотренных тем касающихся систем сборки:
😃 Tuist снова завозит магию.
🤔 Компиляторы vs системы сборки.

В Swift существует три разные сущности:

swift-build - ядро системы сборки, реализованное в репозитории swift-build.
• Он основан на llbuild и служит единым движком, который может планировать и исполнять сборочные задачи для разных фронтов;
• Он не знает напрямую о форматах .xcodeproj или Package.swift. Вместо этого он оперирует промежуточным представлением проекта, называемым PIF (Project Intermediate Format) — абстрактный граф сборки;
• Это то, что Xcode и SwiftPM используют под капотом для фактической сборки после того как манифесты/проекты интерпретированы и конвертированы в PIF.

swift build - система-сборки для сборки Swift Package Manager.
• cобирает только SwiftPM-пакеты (Package.swift);
• парсит манифест, строит граф таргетов, генерирует PIF и передаёт его движку сборки;
• вызывает движок сборки (swift-build вместе с опцией --build-system=swiftbuild).

xcodebuild - система-сборки Xcode-проектов/воркспейсов.
• читает .xcodeproj/.xcworkspace и Build Settings;
• разрешает схемы, таргеты, зависимости;
• конвертирует Xcode-конфигурацию в PIF;
• затем передаёт PIF в swift-build для фактического исполнения.

То есть xcodebuild не вызывает swiftc напрямую через жесткие встроенные правила — он сначала интерпретирует проект, генерирует промежуточное представление и затем передаёт его в swift-build для сборки.


#L #xcodebuild #swiftbuild

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
4
🤖 Все, что нужно знать о push-уведомлениях в iOS
Иногда одна статья хорошо подсвечивает, насколько push-уведомления в iOS — это не «показать алерт», а сложная система с правилами, состояниями и ограничениями.
Вот пример такого триггера для размышлений.

За пушами скрывается гораздо больше:
- Apple Developer Account, ключи APNs и сертификаты
- Permissions и почему токен ≠ разрешение
- Alert, Rich, Silent и VoIP пуши
- Почему PushKit нужен для VoIP
- Зачем VoIP push обязан приводить к CallKit
- mutable-content и content-available
- Extensions и их реальные ограничения
- Как backend общается с APNs
- Background, suspended state и лимиты фоновой работы

Большая часть багов с пушами появляется не в коде UI, а на стыке этих слоёв и ожиданий от системы.
Если будет интересно — могу разобрать весь lifecycle пуша целиком: от создания ключей в Apple Developer до пробуждения приложения в фоне и реальных ограничений iOS.

#L #Push

👏
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥93
😏 SwiftUI: почему Group всё ещё считается вредным

Почитал интересную статью от Two Cent Studios про контейнер Group в SUI – и она очень точно формулирует проблему, с которой многие сталкивались, но не сразу могли понять.

🍕 Что вообще такое Group
В 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, особенно при условиях

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

Что использовать вместо Group
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
💯53🔥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 минут вместо нескольких спринтов самостоятельной разработки. Но за этим стоят множественные скрытые риски. Разработчики часто идут на это из-за жёстких дедлайнов, сложности задачи или давления бизнеса и не всегда задумываются о долгосрочных последствиях

😖Основной недостаток на наш взгляд - это зависимость от maintainers библиотеки (vendor lock), из-за чего зачастую следуют:

🔺 Новые неожиданные баги с обновлениями версии 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
🔥532
😒 Claude Code + XcodeBuildMCP + xcodemake.
Попытка сделать быстрые инкрементальные билды для 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
22
😄ARC, что внутри?

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

⚡️Самый важный момент:

ARC "живет" только при компиляции


Он не отслеживает объекты в рантайме, не решает, когда освобождать память. Его задача - вставить в скомпилированный код вызовы функций, которые при MRC в Objective-C разработчик расставляет самостоятельно:

👉 objc_retain(ptr) - увеличивает счетчик ссылок объекта
👉 objc_release(ptr) - уменьшает счетчик
👉 objc_autorelease(ptr) - отложенное уменьшение счетчика, сегодня редкий кейс, об этом чуть ниже

Роль рантайма же - слепое исполнение инструкций. Если счётчик достигает нуля, объект немедленно деаллоцируется: вызывается deinit, освобождаются stored-свойства, память возвращается в кучу.

Что до счётчика ссылок - он хранится в заголовке объекта в куче и создаётся при аллокации объекта. Из Swift-кода доступа туда не получить

🤔 Что по autorelease?

Используется редко, но стоит упомянуть в контексте 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
5🔥321
😏 Использование семантического версионирования (SemVer) — важный шаг к осознанному выпуску продуктов.

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
433