iOS Broadcast
Open in Telegram
Подборка новостей и статей для iOS разработчиков. Новости Kotlin и мультиплатформы @kotlin_broadcast Новости Android @android_broadcast Реклама и прочее @ab_manager
Show more3 532
Subscribers
+124 hours
+27 days
-930 days
Posts Archive
3 531
+9
🔨 Xcode 27: Apple встраивает агента не в чат, а в весь цикл разработки
В этом году вопроса "с чего бы начать просмотр сессий с WWDC" не стояло, начинаем с "Что нового в Xcode 27"! Главная мысль из сессии - агент становится частью IDE, а IDE частью цикла разработки приложения. От идеи и прототипа до локализации, тестов, Device Hub, production-метрик, Instruments и Xcode Cloud. Ide залезает как на этап Discovery по работе с гипотезами, так и на этап приемки, тестирования и поддержки.
Ключевые изменения:
🟢Агенты живут прямо в редакторе
🟢Команда
/plan позволяет сначала попросить агента собрать контекст и предложить план без изменений в коде
🟢Изменения, артефакты и скриншоты агента видны рядом, пока он работает с проектом
🟢Device Hub становится отдельным рабочим окном для симуляторов и физических устройств
🟢iPhone Mirroring в macOS 27 можно ресайзить, и Apple прямо говорит: проверяйте, как iPhone-приложение живёт в новых размерах окна
🟢Агент может подготовить проект к локализации: пройтись по строкам, создать String Catalog, перевести UI strings и использовать контекст проекта + специфические правила конкретного языка
🟢Organizer теперь не просто показывает что что-то сломалось, а пытается подсказать, что чинить
🟢Instruments получил Top Functions - быстрый способ увидеть, где приложение реально тратит время, особенно когда дорогая операция выполняется много раз
Apple явно не стремится заменить разработчика агентом. Скорее наоборот: Xcode 27 подталкивает к роли, где разработчик задаёт рамки, ревьюит план, проверяет результат и принимает инженерные решения. Агент забирает на себя грязную рутину: подготовить локализацию, собрать контекст, предложить фикс, найти дорогую функцию, помочь провести регресс. Полезная мысль: если проект хаотичный, без тестов, без нормальных сценариев проверки и без метрик, агенту тоже будет не на что опереться. Xcode 27 делает AI-разработку практичной только там, где уже есть инженерная дисциплина. Подумайте о том как выглядит разработка в вашем продукте, есть ли у вас все этапы? Чем лучше проект описывает сам себя через тесты, локализации, метрики, логику сборки и пользовательские сценарии, тем эффективнее в нём будет агент3 531
+9
🎹 Platforms State of the Union: Apple собирает AI-стек для разработчиков
Если keynote был про смотрите, у нас теперь AI, то Platforms State of the Union — про то, как Apple хочет встроить AI прямо в рабочий цикл разработки
🟢Foundation Models framework
Новое поколение Apple Foundation Models доступно через расширенный framework. Пока приложение не популярное - для разработчика бесплатно
🟢On-device AI стал серьёзнее
Модели на устройстве научились мультимодальности и работе с изображениями. Небольшие image-модели можно запускать прямо на телефоне
🟢Private Cloud Compute
Подписчики iCloud+ получат расширенный доступ к серверным моделям через Private Cloud Compute
🟢Core AI
Новый framework для запуска моделей на устройствах. Плюс RAG на основе данных из Spotlight
🟢Динамические профили
Prompt + model + depth reasoning под разные задачи. По сути — имитация разных агентов внутри одного workflow
🟢App Intents + Siri
Достаточно описать entity и intent-схемы. Пользователь говорит Siri свободной формой, а framework сам мапит запрос на возможности приложения
🟢Agentic Coding в Xcode
Теперь это не просто "напиши мне код". Apple раскладывает процесс по стадиям:
🔵discovery — обсуждаем идею с агентом прямо в Xcode
🔵plan — агент создаёт Markdown-план, его можно править руками
🔵development — агент пишет код по согласованному плану
🔵verification — тесты, API, user flows на симуляторе, отчёт
🔵crashes — анализ prod crash, воспроизведение, описание и фикс
🟢Плагины
Всё это работает через плагины. Часть написана инженерами Apple, но Apple явно ждёт, что разработчики будут добавлять свои
🟢Xcode стал практичнее
MCP / Agent Client Protocol, интеграции с популярными агентами, кастомный toolbar, загрузка проектов до 30% быстрее, надёжнее debug и меньший размер
🟢DeviceHub
Simulator заменили новым DeviceHub: в одном месте симуляторы со всеми настройками и физические девайсы
🟢Локализация в Xcode
Перевод теперь можно делать прямо в IDE. Важно: Xcode смотрит не только на строки, но и на контекст, где они используются
🟢SwiftUI снова продают как будущее
В том числе как путь для переписывания web-приложений через agentic coding.
Появились
.reorderContainer, swipe-действия для элементов контейнера и ощущение дежавю: примерно это же когда-то красиво продавали в UICollectionView
🟢SwiftUI performance
@State сделали ленивым, AsyncImage получил кеширование. Это должно ускорить SwiftUI-приложения без доработок
Из важного:
🟡Платформенный сдвиг
Intel Mac — всё. Теперь только Apple Silicon
🟡iPhone Mirroring
В iOS 27 можно менять размер iOS-приложения на Mac и iPad при использовании iPhone Mirroring3 531
+9
🎹 Keynote highlights
WWDC26 получилась больше похожа на Google IO, все вокруг.. Для разработчиков главное начнётся на Platforms State of the Union. То что хоть немного меня зацепило:
🟢iOS 27. Поддерживает все модкли, начиная с iPhone 11, запуск приложений до 30% быстрее
🟢Детские аккаунты. Больше контроля: покупки, сайты, контакты, сообщения и лимиты по категориям контента
🟢Apple Intelligence. Главный акцент — приватность: on-device, Private Cloud Compute и внешние модели там, где нужно
🟢Siri AI. Отдельное приложение, больше контекста, Visual Intelligence и сценарии поверх приложений
🟢App Intents. Самый важный пункт для разработчиков: приложения должны стать понятными новой Siri
🟢Foundation Models. Apple + Gemini: гибридная AI-архитектура вместо попытки делать всё в одиночку
🟢Shortcuts. Вайбкодинг для автоматизаций: описываешь задачу, система собирает сценарий
🟢Xcode. Agentic coding со сторонними моделями: Codex, Claude и Gemini. Ждём деталей по тестам, правкам и границам доступа
🟢DeviceHub. Новое приложение для управления устройствами. Интересно, дадут ли API и intents
🟢Остальные платформы. iPadOS, macOS, watchOS, tvOS и visionOS тоже обновились, но главный разработческий разбор — после SDK и сессий
Мой вывод такой - Keynote дал направление, а не ответы. Теперь смотреть Platforms State of the Union, Xcode, App Intents, AI API и первые developer betas 🍿
3 531
Чуть больше чем через час уже начнется трансляция WWDC26 Keynote! Давайте попробуем ввести немного интерактива в этот WWDC Keynote, делитесь в комментариями фото мест просмотра Keynote, мыслями что ждете от Apple в этом году, а в процессе ивента и после обсудим первые впечатления о новинках Apple. Вот так, например мы организовали офис в Воронеже под просмотр Keynote. Мои мысли уже в комментариях
3 531
🧑💻 WWDC26
Сегодня начинается WWDC26, полезные ссылки:
🍏 Трансляция на сайте Apple
🈸 Трансляция в приложении Apple Developer
🎞 Трансляция на YouTube
🎞 Get ready for WWDC26 — короткое видео Apple о том, как выжать максимум из недели
📅 Расписание WWDC26
🖼 WWDC26 wallpapers - новые обои для Mac, iPad и iPhone
🎧 WWDC26 Hello playlist - плейлист Apple Music для настроения
💬 Apple Developer Forums - место, где обычно быстро всплывают первые вопросы по новым SDK
📦 Downloads — сюда идем после анонсов за beta SDK, Xcode и сопутствующими инструментами
Время UTC+3 / московская тайм-зона:
20:00 Apple Keynote
23:00 Platforms State of the Union
Сессии и материалы будут доступны в Apple Developer, на сайте и на YouTube. Нас ждёт самая насыщенная неделя для iOS-разработчиков: новые SDK, Xcode, SwiftUI, Apple Intelligence и всё то, что завтра придётся аккуратно приносить в реальные проекты 🥂
3 531
+3
🐥 Swift в браузере: кейс Goodnotes, который стоит прочитать iOS‑командам
Иногда кроссплатформенность звучит как "давайте перепишем всё на что-нибудь универсальное и будем страдать одинаково везде". Кейс Goodnotes интереснее: команда взяла большой Swift-код iPad-приложения и вынесла его в web через WebAssembly, не превращая продукт в демо ради конференции.
По цифрам там всё серьёзно: 2,2 млн строк Swift в web-версии, из них 1,47 млн строк общего кода. Общими оказались не кнопочки, а дорогая часть: движок рендера, модель документов, распознавание рукописного ввода, индексации, ViewModel-и. UI и платформенные интеграции остались разными.
Если бизнес-логика, I/O и concurrency прибиты гвоздями к UIKit, GCD и конкретной платформе, то никакой WebAssembly, server-side Swift или будущий SDK вас красиво не спасёт.
О чем я бы задумался:
🟢где доменная логика зависит от UIKit/SwiftUI/Foundation API без реальной причины
🟢есть ли абстракции для network, storage, analytics, feature flags и clock
🟢не спрятаны ли
DispatchQueue, locks и callbacks внутри кода, который можно перевести на async/await
🟢нет ли предположений вроде Int всегда 64-bi» в форматах, индексах, offsets и persisted data
Портируемость начинается не с платформы, а с границ
Хороший маленький тест: можно ли прогнать core-логику в обычном Swift Package без симулятора и без UIApplication? Если нет, проблема обычно не в WebAssembly, а в архитектуре
protocol NotesAPI {
func document(id: DocumentID) async throws -> Document
}
struct DocumentIndexService {
let api: NotesAPI
let clock: any Clock<Duration>
func rebuild(id: DocumentID) async throws -> SearchIndex {
let document = try await api.document(id: id)
return SearchIndex(document: document)
}
}
Этот код скучный, зато именно такая скука потом позволяет запускать тесты быстро, менять transport без переписывания core и аккуратно выносить части продукта в другие окружения. AI-generated code часто усиливает старые архитектурные привычки: если в проекте всё связано со всем, агент будет быстро генерировать ещё больше такого же кода3 531
+3
🧵 Swift в браузере: кейс Goodnotes, который стоит прочитать iOS‑командам
Иногда кроссплатформенность звучит как «давайте перепишем всё на что-нибудь универсальное и будем страдать одинаково везде». Кейс Goodnotes интереснее: команда взяла большой Swift-код iPad-приложения и вынесла его в web через WebAssembly, не превращая продукт в демо ради конференции.
По цифрам там всё серьёзно: 2,2 млн строк Swift в web-версии, из них 1,47 млн строк общего кода. Общими оказались не кнопочки, а дорогая часть: rendering engine, document model, распознавание рукописного ввода, indexing, view models. UI и платформенные интеграции остались разными.
Для iOS-разработчика главный вывод не «срочно пишем сайт на Swift». Главный вывод: если бизнес-логика, I/O и concurrency прибиты гвоздями к UIKit, GCD и конкретной платформе, то никакой WebAssembly, server-side Swift или будущий SDK вас красиво не спасёт.
Что я бы проверил в проекте:
🟢 где доменная логика зависит от UIKit/SwiftUI/Foundation API без реальной причины;
🟢 есть ли абстракции для network, storage, analytics, feature flags и clock;
🟢 не спрятаны ли
DispatchQueue, locks и callbacks внутри кода, который можно перевести на async/await;
🟢 нет ли предположений вроде «Int всегда 64-bit» в форматах, индексах, offsets и persisted data.
Портируемость начинается не с платформы, а с границ
Хороший маленький тест: можно ли прогнать core-логику в обычном Swift Package без симулятора и без UIApplication? Если нет, проблема обычно не в WebAssembly, а в архитектуре.
protocol NotesAPI {
func document(id: DocumentID) async throws -> Document
}
struct DocumentIndexService {
let api: NotesAPI
let clock: any Clock<Duration>
func rebuild(id: DocumentID) async throws -> SearchIndex {
let document = try await api.document(id: id)
return SearchIndex(document: document)
}
}
Этот код скучный, зато именно такая скука потом позволяет запускать тесты быстро, менять transport без переписывания core и аккуратно выносить части продукта в другие окружения.
Это стало особенно актуально сейчас:
🟡 до WWDC26 остаётся меньше недели, и новые SDK почти наверняка снова поднимут вопрос границ между app code, tooling, AI-assisted workflows и платформенными API;
🟡 AI-generated code часто усиливает старые архитектурные привычки: если в проекте всё связано со всем, агент будет быстро генерировать ещё больше такого же кода.
Я бы вынес отсюда практичный шаг на эту неделю: выбрать один важный сервис и попробовать собрать его как отдельный Swift Package с тестами. Не ради моды на кроссплатформенность, а ради более понятной, проверяемой и живучей iOS-кодовой базы.3 531
🧵Actor без state — это баг архитектуры или нормальный инструмент?
Кажется, Swift Concurrency опять подкинула тему - акторы, у которых нет собственных свойств и вроде бы нечего защищать. Кажется что Actor же нужен, чтобы изолировать mutable state. Нет state — нет смысла? Но иногда actor используют не только как сейф для данных, а как способ явно сказать компилятору и рантайму: этот кусок работы не должен жить на
MainActor, его можно безопасно передавать между задачами, а синхронная часть должна выполняться в изоляции.
Например, типичный NetworkClient:
actor NetworkClient {
func loadCart() async throws -> [Product] {
let (data, _) = try await URLSession.shared.data(for: cartRequest)
return try JSONDecoder().decode([Product].self, from: data)
}
}
У него может не быть состояния вообще. Но actor всё равно даёт пару эффектов: тип становится Sendable, а синхронная работа внутри метода не уедет на main thread. Для JSON decoding это уже не совсем косметика.
Что я бы проверил в проекте:
🟢есть ли у ваших actors реальное состояние, которое они защищают;
🟢не используются ли actors просто как “модный async-сервис”;
🟢нет ли сериализации там, где нужна параллельная обработка;
🟢не появился ли actor только потому, что так проще заткнуть Sendable-ошибки;
🟢понятно ли, что будет больнее: добавить actor сейчас или убрать его через полгода.
Главная ловушка — actor сериализует синхронные куски работы
Если в NetworkClient прилетит много запросов, actor не будет параллельно декодировать ответы сколько угодно широко. Его изолированная синхронная работа идёт последовательно. Иногда это именно то, что нужно. А иногда вы случайно сделали бутылочное горлышко там, где хотели просто безопасный сервис.
Альтернатива может выглядеть так:
struct NetworkClient: Sendable {
@concurrent
func loadCart() async throws -> [Product] {
let (data, _) = try await URLSession.shared.data(for: cartRequest)
return try JSONDecoder().decode([Product].self, from: data)
}
}
Это не значит что struct всегда лучше actor. Скорее наоборот: если actor появился, нужно уметь объяснить, какую проблему он решает. Защищает cache? Синхронизирует доступ к файловой системе? Интегрируется с legacy queue через custom executor? Отлично.
Если ответ "просто делает сервис более concurrency-friendly” - тут уже стоит притормозить.
Отдельно важный кейс — файловая система
У actor может не быть state в виде properties, но state может жить снаружи: файлы, директории, on-disk cache. Компилятор этого не видит, зато гонки там вполне настоящие. В таком случае "пустой" actor может быть нормальной границей, которая сериализует доступ и не даёт разным частям приложения одновременно ломать один и тот же cache.
Это стало особенно актуально сейчас:
🟡Swift 6 всё сильнее заставляет думать про isolation и Sendable, а не просто писать async вокруг старого кода
🟡AI-агенты легко генерируют actors на любой чих, потому что это выглядит современно и компилятор часто становится тише
🟡но actor — это не декоратор безопасности, а синхронизационный примитив со стоимостью, очередью и архитектурными последствиями
Хорошее правило простое: если в коде появился actor, рядом должен быть внятный ответ, что именно он изолирует. Не обязательно property внутри себя. Это может быть UI, файловая система, serial executor или будущий cache. Но если ответ звучит как "ну, так вроде правильнее для async/await", значит это место лучше открыть в Instruments и в голове, пока оно не стало частью архитектуры.3 531
😄 AI в разработке: время новых процессов
Сейчас уже поздно спорить о том, нужен ли AI в разработке: он прочно вошёл в процессы — и в стартапах, и в бигтехе.
Эксперты Podlodka AI Crew собрали сезон «AI-First Development», чтобы обсудить уже не отдельные инструменты, а новую инженерную модель, в которой AI становится частью команды.
На конференции с 15 по 19 июня:
🗒️ Разберем, как делать AI-разработку более предсказуемой с помощью Open Spec Development
⚡️ Изучим model routing и prompt caching
⚙ Узнаем, как автоматизировать инженерные процессы с помощью AI
🤖Обсудим навыки и оркестрацию AI-агентов
⚡️ Посмотрим, как AI влияет на качество и скорость разработки.
Формат: пять дней живых Zoom-сессий по утрам и вечерам, закрытое комьюнити в Telegram и обсуждения со спикерами.
🎟 Посмотреть программу и купить билеты по ссылке
Скидка по промокоду
BROADCAST_iOS_AI 🎁 — самая приятная цена для тех, кто успеет первым.
#реклама3 531
+1
🧵 Swift Concurrency опять перестала быть магией
Все уже одной ногой на WWDC и ждут iOS 27, но в iOS-сообществе на этой неделе всплыла куда более приземленная тема: как понять, что реально происходит внутри вашего
async/await. Мне нравится, что разговор снова вернулся к Instruments. Потому что вокруг Swift Concurrency до сих пор есть странное ощущение: раз код асинхронный, значит он автоматически быстрый и правильный. Нет, конечно 😁. Иногда это просто очень аккуратный способ наплодить лишних Task, забить actor, подвесить main thread и потом неделю ловить баг из серии: "на моем телефоне экран иногда тупит, но не всегда".
Свежий материал напоминает: у нас для этого есть не гадание по логам, а нормальные инструменты. В Instruments можно открыть Swift Concurrency template и смотреть не только Time Profiler, но и Swift Tasks, Actors, Hangs — то есть видеть, где код реально ждёт, где конкурирует за actor, а где просто делает больно UI.
Что я бы проверил в проекте:
🟢какие Task живут дольше, чем должны;
🟢нет ли actor contention там, где “просто завернули всё в actor”;
🟢не блокируется ли main thread в коде, который снаружи выглядит асинхронным;
🟢что происходит не на тестовых 20 элементах, а на нормальном объёме данных.
Отдельная мелочь, которая сильно помогает — task names
Без имён в отладке легко получить кашу из безликих задач. С именами хотя бы понятно, что именно сейчас выполняется: загрузка профиля, синк сообщений, рекомендации, кеш, аналитика.
await withTaskGroup(of: Void.self) { group in
group.addTask(name: "Load profile") {
await profileService.load()
}
group.addTask(name: "Load feed") {
await feedService.loadFirstPage()
}
}
Это стало особенно актуально сейчас:
🟡AI-агенты всё чаще пишут Swift-код. И они уже вполне могут собрать экран, завести сервис, добавить async и сделать так, чтобы happy path работал.
Но "собирается" и "нормально ведёт себя под нагрузкой" — это разные вещи. Агенту легко сгенерировать код, который выглядит современно, но плодит лишние задачи, плохо отменяется или держит actor в очереди без видимой причины.
Поэтому хороший цикл теперь такой:
→ написали async-код
→ прогнали реальные сценарии
→ открыли Instruments
→ посмотрели tasks/actors/hangs
Перед WWDC полезнее не гадать, что покажут в iOS 27, а снять baseline текущего проекта на Xcode 26.5. Тогда после новых SDK будет понятно, где проблема Apple, где миграция, а где ваш старый async-код просто наконец попросил внимания.3 531
📱 TimelineView в SwiftUI
Часто при задаче с обновлением UI по времени интуитивно хочется использовать
Timer. Но в SwiftUI не всегда нужно вручную пушить изменения в @State. Правильным подходом будет дать системе таймлайн и сказать пересчитать view по таймлайну. Для этого есть TimelineView:
TimelineView(.everyMinute) { context in
Text(context.date, format: .dateTime.hour().minute())
}
Идея простая:
TimelineView сам сообщает SwiftUI, когда нужно заново вычислить body. А внутри closure вы получаете context.date — дату конкретного обновления. Мой UI зависит от времени, переоцени его по расписанию.
Оптимален такой подход для:
🟢часов и обратного отсчета
🟢виджеты времени внутри экрана
🟢периодически обновляемые visual states
🟢анимированные фоны
🟢Загружаемые загрузки
🟢градиенты и эффекты, которые меняются со временем
В SwiftUI уже есть несколько готовых расписаний:
🟢.everyMinute — обновление в начале каждой минуты
🟢.periodic(from:by:) — обновление с заданным интервалом
🟢.animation — обновление с частотой, подходящей для animated content
Например, если нужно показывать секунды:
TimelineView(.periodic(from: .now, by: 1)) { context in
Text(context.date, format: .dateTime.hour().minute().second())
.monospacedDigit()
}
А если нужно двигать визуальный эффект, можно вообще не хранить progress в @State.
TimelineView(.animation) { context in
let time = context.date.timeIntervalSinceReferenceDate
let hue = (sin(time * 0.2) + 1) / 2
Color(hue: hue, saturation: 0.7, brightness: 0.9)
}
важный сдвиг в мышлении В SwiftUI-модели лучше думать: "У меня есть view, значение которого зависит от времени" .И TimelineView как раз про это, но здесь легко ошибиться:
🟡TimelineView — не замена всем таймерам
🟡его не стоит использовать для бизнес-логики
🟡он не нужен, если вы просто хотите загрузить данные раз в N секунд
🟡он не должен становиться способом запускать side effects из UI
🟡частые обновления могут быть дорогими, особенно если view тяжёлый
Для обновления данных, или фоновой работы и координации логики обычный Timer, async task или background mechanism часто подходят лучше. TimelineView хорош именно тогда, когда меняется сам интерфейс. Ещё интересный момент — context.cadence. SwiftUI может снижать частоту обновлений, если live-updates сейчас не нужны или невозможны. Например, можно показывать миллисекунды только при .live, а при более редком cadence откатываться к обычным секундам.
TimelineView(.animation) { context in
let format: Date.FormatStyle =
context.cadence == .live
? .dateTime.hour().minute().second().secondFraction(.fractional(3))
: .dateTime.hour().minute().second()
Text(context.date, format: format)
.monospacedDigit()
}
И это очень Apple-like подход: не пытаться насильно обновлять UI всегда с максимальной частотой, а адаптироваться к тому, что система считает разумным прямо сейчас3 531
🚫 За что вас могут навсегда заблокировать во Flutter?
Многим кажется, что проекты с открытым кодом — это закрытый клуб для гениев. Тимлид Яндекс Доставки и по совместительству член core-команды Flutter Даниил Липаткин рассказывает, как всё устроено на самом деле.
Спойлер: просто будьте вежливы с людьми, даже когда отправляете код на проверку.
В материале:
🔶 Как выбрать задачу и не сломать проект.
🔶 Почему даже крутой код могут отклонить.
🔶 Как вносить свой вклад вообще без кода.
🔶 За что авторы могут навсегда заблокировать.
Если давно хотели начать писать открытый код, то это тот самый знак!
▶️ Прочитать полную статью можно в блоге Городских сервисов Яндекса
#реклама
3 531
🚫 За что вас могут навсегда заблокировать во Flutter?
Многим кажется, что проекты с открытым кодом — это закрытый клуб для гениев. Тимлид Яндекс Доставки и по совместительству член core-команды Flutter Даниил Липаткин рассказывает, как всё устроено на самом деле.
Спойлер: просто будьте вежливы с людьми, даже когда отправляете код на проверку.
В материале:
🔶 Как выбрать задачу и не сломать проект.
🔶 Почему даже крутой код могут отклонить.
🔶 Как вносить свой вклад вообще без кода.
🔶 За что авторы могут навсегда заблокировать.
Если давно хотели начать писать открытый код, то это тот самый знак!
▶️ Прочитать полную статью можно в блоге Городских сервисов Яндекса
#реклама
3 531
📱 Kerning vs Tracking в SwiftUI
Обожаю подобные заныривания в техничку в вопросах, которые кажутся простыми на первый взгляд. Есть ли разница между первым и вторым примером? Зависит от
Semantics.TextModifiersOverrideParentValues. Аналогично и для .kerning() и .tracking(), это же одно и то же, расстояние между буквами. А потом выясняется, что типографика Apple различает их очень жёстко — и SwiftUI тоже.
Text("SwiftUI")
.kerning(2)
и
Text("SwiftUI")
.tracking(2)
могут выглядеть похоже. Но работают они по-разному.
Главная разница:
🟢kerning влияет на межбуквенные пары с учётом типографических правил
🟢tracking равномерно распределяет spacing между всеми символами
SwiftUI typography — это не просто wrapper над CoreText. У текста есть семантика. Когда вы используете .tracking(), вы говорите системе: "Мне нужен стилистический spacing поверх обычной типографики".
Когда используете .kerning(), вы вмешиваетесь в сами kerning calculations.
Apple сама активно использует tracking в UI:
🟢navigation titles
🟢watchOS labels
🟢Health / Fitness typography
🟢Vision Pro spatial UI
🟢SF Symbols paired text
Потому что tracking помогает интерфейсу "дышать", особенно на маленьких экранах и в semi-transparent UI. Но здесь легко перейти грань. Очень частая ошибка:
🟡tracking используют как “сделать текст дизайнерским”
🟡spacing увеличивают без учёта размера шрифта
🟡all-caps текст превращается в набор разрозненных букв
🟡headline начинает выглядеть как логотип из 2013 года
🟡spacing ломает читаемость быстрее, чем кажется
Особенно это заметно в SwiftUI, потому что system typography у Apple изначально очень хорошо настроена. И чем сильнее вручную крутить spacing, тем проще испортить баланс, который SF Pro уже сделал за вас.
AttributedString и современные text APIs в SwiftUI постепенно двигаются к более семантической модели текста. То есть текст — это уже не просто строка с modifiers. Это структура с типографическими attributes, layout intent и rendering semantics. Именно поэтому TextRenderer, AttributedString и новые typography APIs становятся всё важнее в SwiftUI.3 531
🐥 Анимации в SwiftUI
Изначально, SwiftUI позиционировался как переворот в области лейаута и анимации, все действительно стало проще, но не без нюансов. Если вы думаете о анимациях
.animation(.default) как о магии, то стоит чуть разобраться, ведь магии там ровно столько, сколько SwiftUI может вывести из изменения state.
SwiftUI не анимирует view, он анимирует переход между двумя состояниями интерфейса.
То есть анимация в SwiftUI — это не запусти движение, а плавно интерполируй изменение дерева view после изменения state.
Например:
swift id="x8j3pn"
.animation(.easeInOut, value: isExpanded)
Когда isExpanded меняется — анимируй все связанные изменения layout и modifiers
Где SwiftUI-анимации особенно хороши:
🟢изменение размеров и layout
🟢opacity и appearance/disappearance
🟢state-driven UI
навигация и переходы
Главный плюс SwiftUI — анимация становится частью декларативного описания интерфейса, а не отдельным императивным кодом.
Но есть нюанс:
SwiftUI анимирует не то, что вы ожидаете.
Он анимирует то, что изменилось с точки зрения diffing system.
Именно поэтому иногда:
🟡анимируется “слишком много”
🟡анимируется вообще не тот modifier
🟡transition не срабатывает
🟡view исчезает без анимации
🟡layout начинает “прыгать”
🟡.animation() внезапно влияет на соседние изменения state
Очень важный момент:
.animation() — это не инструкция "анимируй этот view", а "анимируй изменения, связанные с этим value". Поэтому в современных SwiftUI-проектах намного безопаснее:
.animation(.spring(), value: isExpanded)
чем старый глобальный стиль:
.animation(.spring())
Потому что без value: легко получить неявные анимации там, где вы вообще их не планировали.
Отдельно интересно, как SwiftUI работает с transitions.
.transition(.move(edge: .bottom))
Transition срабатывает не когда view “изменился”, а когда он появился или исчез из hierarchy.
То есть условный if isVisible — это не просто условие рендера.
Для SwiftUI это буквально lifecycle элемента в дереве интерфейса.
Именно поэтому transition без withAnimation часто не работает так, как ожидается.
Spring-анимации
Apple уже много лет двигает идею "физического интерфейса", где интерфейс ощущается не идеально линейным, а чуть живым: с обратной связью, velocity и мягкой остановкой.
И SwiftUI springs дают это почти бесплатно:
🟢кнопки ощущаются отзывчивее
🟢cards двигаются естественнее
🟢gestures выглядят менее механическими
🟢интерфейс становится ближе к системному поведению iOS
Но это как раз тот случай, где анимация легко превращается в визуальный шум:
🟡если анимируется каждый state change — интерфейс начинает утомлять
🟡если spring слишком "резиновый" — UI ощущается игрушечным
🟡если layout постоянно перестраивается — появляются дёргания
🟡если animation modifier висит слишком высоко — начинают анимироваться неожиданные вещи
🟡если transition сложнее самой interaction — пользователь чувствует не плавность, а задержку
SwiftUI-анимации — это не про “добавить движения”.
Это про то, чтобы изменение состояния интерфейса ощущалось естественным. Хорошая SwiftUI-анимация обычно почти незаметна. Она не отвлекает пользователя на себя, а помогает мозгу понять: что изменилось, откуда появился элемент и почему интерфейс теперь выглядит иначе.3 531
🎹 Apple Design Awards 2026: кого Apple выбрала и почему
Apple опубликовала финалистов Apple Design Awards 2026 — и это не просто список красивых приложений. По сути, это редакционный шорт-лист того, каким Apple хочет видеть современный софт под свои платформы: нативным, аккуратным к деталям, инклюзивным, хорошо использующим железо и фреймворки. Мои инсайты:
1. Маленькие, законченные идеи
Blippo+ — это ретро-футуристичное телевидение”с синхронизированной трансляцией для всех пользователей
Metaballs — visionOS-эксперимент с пространственными blob-объектами, материалами и светом
grug — почти антипродукт: маленькое приложение с ежедневной “пещерной мудростью”, ручным стилем и без лишних аккаунтов, облака и усложнений
Apple ценит не только масштаб, иногда важнее цельность идеи: маленькая механика, но доведённая до идеала.
2. Accessibility
Guitar Wiz — инструмент для гитаристов с VoiceOver, Dynamic Type, Increased Contrast и подсказками по аккордам.
Hearing Buddy — приложение от инди разработчика с нарушением слуха, которое использует on-device speech-to-text и Foundation Models для субтитров в реальном времени и саммаризации
Structured — планировщик, который помогает не только забивать календарь задачами, но и находить место для отдыха, что особенно ценно для neurodivergent-пользователей.
Главный сигнал: ценно когда продукт изначально спроектирован вокруг реальных ограничений, привычек и контекста пользователя.
3. AI и Foundation Models
Сразу несколько финалистов подсвечены именно за использование Foundation Models и on-device обработки.
Detail: AI Video Editor превращает черновик или outline в teleprompter script и помогает авто-монтировать видео.
Hearing Buddy делает captions и summaries разговоров.
Structured использует Foundation Models, чтобы предлагать и предзаполнять задачи.
Harvee переводит данные Apple Watch про сон, пульс и recovery в понятные рекомендации — при этом чувствительные health-данные остаются на устройстве.
Apple явно показывает: AI-фичи должны быть частью конкретного UX-сценария, желательно — приватно и локально.
4. visionOS всё ещё ищет killer apps
Вангую что это последний год для VisionOS
Apple Design Awards 2026 — это подсказка разработчикам, какие продукты Apple сейчас считает образцовыми:
🟢маленькие, но законченные идеи
🟢нативный UX вместо абстрактного кроссплатформенного слоя
🟢accessibility как часть архитектуры продукта
🟢on-device AI вместо “прикрутили чатбота”
🟢visionOS как отдельная spatial-платформа, а не второй монитор
🟢интерфейсы, которые реально адаптированы под новую дизайн-систему
🟢impact, который ощущается в механике, а не только в маркетинге3 531
🐥 Флаки тесты и Swift Concurrency
Если вы не знакомы с термином флаки тестов - вам повезло. Обычно такие тесты падают крайне редко, но на большом объеме тестов это становится заметно. Иногда flaky test — это просто плохо написанный тест, но иногда что-то более сложное.
Например в случае многопоточности это может показать что вы не до конца понимаете, где именно выполняется ваш async-код.В статье разбирается как раз такой кейс с
IntervalDebouncer: маленький @MainActor-класс, который должен вызвать action после debounce-интервала.
Тест выглядит почти очевидно:
self.sut.debounce { callCount += 1 }
await self.clock.advance(by: .seconds(0.3))
XCTAssertEqual(callCount, 1)
Но тест начинает флакать. И проблема не в том, что Swift Concurrency «рандомная».
Проблема в том, что мы часто мысленно всё ещё живём в модели очередей и потоков, а Swift Concurrency работает через tasks, actors, executors и isolation.
Task — это не thread
@MainActor — это не просто main queue
await — это не просто подожди тут
Task.yield() — это не дай выполниться всему async-коду в приложении
Особенно неприятный момент: Task.yield() уступает выполнение текущему executor’у, но не гарантирует, что нужная вам задача на другом executor’е уже успела выполниться.
Именно поэтому тесты с mock clock, debounce, sleep, timers и @MainActor могут выглядеть детерминированными, но периодически падать.
Где это особенно легко поймать:
🟢тесты debounce/throttle-логик и
🟢кастомные Clock / MockClock
🟢код под @MainActor
🟢unit-тесты, где вы ожидаете “после await всё уже случилось”
🟢утилиты, которые должны работать в actor context вызывающего кода
🟢асинхронные тесты, где есть несколько tasks и ожидание порядка выполнения
Практические советы:
🔵думайте не только на каком потоке идет исполнение, а на каком actor/executor
🔵не используйте Task.yield() как универсальный способ стабилизировать тест
🔵не считайте await гарантией, что все связанные задачи уже завершились
🔵если utility-функция должна выполняться в isolation вызывающего кода — смотрите в сторону isolated parameters и #isolation
🔵если тест проверяет время — делайте время явной зависимостью, а не надейтесь на настоящий scheduler
🔵если тест флейкает — сначала проверьте execution context, а не добавляйте случайные sleep-ы
Но это как раз тот случай, где flaky test оказался полезнее зелёного теста.
Он показал, что проблема не в одном MockClock, а в неправильной ментальной модели:
🟡actor isolation не означает всё выполняется последовательно как транзакция
🟡Task может стартовать не тогда, когда вы этого ожидаете
🟡после suspension point выполнение может продолжиться уже в другом контексте
🟡scheduler не обязан выполнять задачи в том порядке, который кажется очевидным из кода
🟡детерминированный тест требует детерминированной модели ожидания, а не надежды на timing
Swift Concurrency делает асинхронный код безопаснее, но не делает его автоматически очевидным. Флакающие тесты в async-коде это не "плохой CI" и не про "поставить sleep побольше", они про то, что в коде неявно смешались tasks, actors, executors и ожидания из старого GCD-мышления. И чем раньше такой тест упадёт локально, тем меньше шансов потом ловить тот же баг в production.3 531
🐥 Swift 6 краши при многопоточности
Если вам кажется что Swift 6 strict concurrency - это просто больше compile-time проверок - это не так. Часть проблем ловится уже в runtime, причём иногда прямо в production. Даже если проект собирается без warnings, Swift может вставить dynamic isolation checks на границах акторов и GCD. И если код ожидал один execution context, а приехал в другой — приложение упадет 😥. Чаще всего в crash reports это выглядит так:
_dispatch_assert_queue_fail
_swift_task_checkIsolatedSwift
Суть проблемы простая: closure или метод унаследовал actor isolation там, где был объявлен, а вызвали его потом из другого потока. Например, closure внутри @MainActor context может неявно стать main-actor-isolated. А потом вы передаёте её в context.perform у Core Data, который выполняет блок на своей private queue.
Где это особенно легко поймать:
🟢Core Data context.perform из @MainActor-кода
🟢Combine pipeline, где operator выполняется до receive(on:)
🟢NotificationCenter publisher, если notification прилетает с background thread
🟢delegate callbacks от SDK, которые не обещают main thread
🟢MainActor.assumeIsolated, если вы на самом деле не на MainActor
🟢actor methods, где после await состояние уже могло измениться из-за reentrancy
Практические правила:
🟢если Combine-operator должен работать на main — ставьте .receive(on: DispatchQueue.main) до него, а не после
🟢если closure не должен наследовать actor isolation — явно помечайте его @Sendable
🟢если delegate может прийти не с main thread — делайте метод nonisolated, а UI-работу отправляйте в Task { @MainActor in ... }
🟢не используйте MainActor.assumeIsolated как красивую замену await MainActor.run
🟢не рассчитывайте, что @MainActor на всём классе автоматически безопасен для всех callback’ов
Swift 6 начал громко показывать то, что раньше было скрытой проблемой:
🟡closure наследует isolation от места объявления, а не от места выполнения
🟡receive(on:) не спасает код, который уже выполнился до него
🟡delegate от системного SDK не обязан приходить на main thread
🟡билд без ворнингов не гарантирует отсутствие рантайм крашей из-за многопоточности
🟡после await внутри actor нельзя слепо доверять старому состоянию
Swift 6 concurrency — это не только про то, чтобы пофиксить warnings, это про пересмотр границ - где выполняется код, кто владеет состоянием и какой thread/actor реально вызывает callback.3 531
🐥 Actors vs Queues vs Locks в Swift
Статья достойная добавления в закладки, все чётко и по-полочкам про то как защитить shared state, плюсы и минусы решений, все то что полезно понимать не только для собеседований
➡️actor — это защита состояния на уровне языка
➡️DispatchQueue — это ручная сериализация выполнения
➡️Lock — это низкоуровневый замок вокруг маленького участка кода
Все три решают похожую проблему, но совершенно разной ценой. Где хорошо заходят actors:
🟢когда код уже живёт в Swift Concurrency
🟢когда состояние логически принадлежит отдельной сущности
🟢когда хочется, чтобы компилятор помогал с isolation и Sendable
🟢когда нормальная async-модель доступа через await
Actors хороши не потому, что они новые. а потому что они делают границы доступа явными.
Но есть нюанс: await внутри actor-метода — это точка, где атомарность ломается. Actor защищает от одновременного доступа к состоянию, но не отменяет «перезаходы» и не превращает логику в транзакцию
Где всё ещё уместны queues:
🟢когда есть legacy-код на GCD
🟢когда нужно аккуратно сериализовать работу без полной миграции на async/await
🟢когда вокруг много callback-based API
🟢когда уже есть понятная очередь на подсистему: database queue, storage queue, parsing queue
DispatchQueue — не старый плохой способ, а просто это инструмент, где порядок, блокировки и переходы между очередями вы контролируете сами. А значит, сами же отвечаете за дедлоки, лишние переключения контекстов и внезапную сложность.
Где могут выигрывают locks:
🟢когда нужен очень маленькая синхронизация в критической секции
🟢когда доступ должен быть мгновенным, без await
🟢когда вы защищаете простое значение или короткую операцию
🟢когда actor был бы архитектурно тяжелее самой проблемы
Но locks — это как раз тот случай, где просто заверну в NSLock легко превращается в мину:
🟡у компилятора почти нет понимания вашей синхронизации
🟡нельзя держать lock через await
🟡длинный critical section быстро портит производительность
🟡неправильный порядок lock’ов-привет, deadlock
🟣Actors — хороший дефолт для нового async-кода.
🟣Queues — практичный мост для существующей архитектуры.
🟣Locks — точечный инструмент для маленьких синхронных участков.
Не нужно заменять всё на actors только потому, что Swift 6 стал строже. Не нужно тащить locks туда, где на самом деле нужна нормальная модель владения и изоляции.
3 531
📱 Background Refresh в SwiftUI
На iOS запустить что либо точно когда хочется не получится, но вот попросить систему и добиться ожидаемого поведения в большинстве случаев возможно. Для этого есть
BGAppRefreshTaskRequest — это не cron, а просьба к системе: разбуди приложение не раньше указанного времени, если посчитаешь это уместным.
В SwiftUI это теперь выглядит довольно аккуратно:
.backgroundTask(.appRefresh(taskID)) {
await dataProvider.loadData()
}
Но перед этим всё равно нужно пройти классический набор:
🟢включить Background Modes в Capabilities
🟢добавить Background fetch
🟢зарегистрировать task identifier в Info.plist
🟢запланировать BGAppRefreshTaskRequest
🟢повесить handler через .backgroundTask
Но у этого способа есть целый набор юзкейсов:
🟢обновить кеш до следующего запуска приложения
🟢подтянуть свежий контент для первого экрана
🟢сделать так, чтобы пользователь чаще видел готовые данные, а не спиннер
🟢аккуратно обслуживать локальные данные без явного открытия приложения
На практике это хороший паттерн для приложений с ежедневным или периодическим контентом:
при запуске показываем кеш, при необходимости обновляем данные, после успешного обновления планируем background refresh на следующий раз. Но важно не перепутать инструмент с гарантией:
🟡earliestBeginDate не гарантирует запуск в конкретное время
🟡система может вообще не дать фонового окна
🟡нельзя завязывать на это критичную бизнес-логику
🟡фоновой задаче нужно уложиться примерно в 30 секунд
🟡если регулярно не укладываться, iOS может начать реже давать такие запуски
Для долгих сетевых операций нужен background URLSession.
Для тяжёлой обработки — BGProcessingTaskRequest. Background Refresh — это не способ выполнять работу «когда захотим», а способ подготовить приложение к следующему открытию.
Available now! Telegram Research 2025 — the year's key insights 
