Первые дни новогодних праздников позади, а значит пора возвращаться к контенту. Что может быть лучше для начала года чем лекции Стенфорда. Пятая лекция сосредотачивается на архитектуре приложений, модели состояния и связке с UI — это следующий логичный шаг после первых четырёх лекций
@StateObject, @ObservedObject, @Binding и реактивное обновление View.enum, структуры и Optional для описания состояния приложенияВсе эти подходы помогают перейти от простого UI к полноценному приложению с бизнес-логикой, состояниями и тестируемой моделью
Почему это полезно?
#cs193p
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13
iOS Broadcast
Новая лекция из курса iOS Development with SwiftUI от Stanford University продолжает тему архитектуры приложений на SwiftUI — от базового разделения Model/View/ViewModel к более сложным паттернам устойчивости и масштабируемости. Лекция полностью состоит из демонстрации, на основе которой после лекции формируется домашнее задание.
Продвинутая архитектура SwiftUI-приложений:
Observable, @MainActor, ViewModelsСвязь Model ↔️ ViewModel ↔️ View
@Published, Binding, @StateObject)Работа с навигацией и состоянием
Домашнее задание:
Создать игру, похожую на CodeBreaker (которую создают в курсе), но с буквами английского алфавита вместо цветных меток, а также со следующими требованиями:
#cs193p
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Оказывается есть аналог глобального AGENTS.md для каждого проекта. Можно настроить общие подходы через скилы.
Skills заменяют AGENTS.md
Skill — это каталог, содержащий:
Skills позволяют разделять знания по темам, например:
и использовать их во всей своей экосистеме AI-инструментов
Автор создал Swift Concurrency Skill с модульной структурой:
swift-concurrency/
├── SKILL.md
└── references/
├ async-await-basics.md
├ actors.md
├ tasks.md
├ memory-management.md
└ …
Это даёт агенту глубокий, структурированный контекст, когда он отвечает на вопросы или делает refactor/анализ кода
Преимущества подхода
Agent Skills эффективно превращают набор практик и знаний вашего стека в модульные, переиспользуемые блоки. Это даёт:
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Google и Apple опубликовали совместное заявление, что само по себе редкость. Компании подчеркнули общее видение будущего цифровой экосистемы - AI с акцентом на безопасность, приватность и ответственность крупных платформ.
Факт - бизнес Apple не строится на продаже пользовательских данных
Именно поэтому Apple может:
Для компаний, живущих за счёт рекламы и данных, такой подход просто недоступен.
На этом фоне совместное заявление Apple и Google выглядит не компромиссом, а расчётливым шагом:
Gemini — один из самых зрелых AI-стеков
И ключевое — Gemini легко встраивается как внешний сервис, без передачи контроля над платформой.
Apple делает то, что умеет лучше всего:
Gemini здесь — инструмент, а не хозяин экосистемы.
Apple усиливает платформу, используя privacy как рычаг, а Gemini — один из немногих AI-партнёров, которого можно встроить, не ломая эту модель.
Верите в успех этого партнерства или расстроены тем что Apple признали свое отставание и сдались вендору в плоскости AI?
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Добавить напоминание в дефолтный список — легко.
Но как только у вас появляются кейсы типа Проекты / Контексты / Приоритеты, всё ломается:
Искушение: писать в default list и забыть
EKReminder в defaultCalendarForNewReminders() — и кажется, что задача решена. Но это не UX, а технический костыль.Рабочий подход: создавать свои списки (reminder lists) через
EKCalendarEKCalendar c entity .reminder)Что делаем:
requestFullAccessToReminders()eventStore.calendars(for: .reminder)EKCalendar(for: .reminder, eventStore: ...), задаём noscript, подбираем source, сохраняем saveCalendar(..., commit: true)EKReminder, выставляя dueDateComponents и сохраняя eventStore.save(reminder, commit: true)Info.plist — Privacy - Reminders Full Access Usage Denoscription.Списки Reminders должны сохраняться в конкретное хранилище (локально / iCloud / CalDAV). Авторы предлагают приоритет:
.local или .calDAV, иначе fallback на defaultCalendarForNewReminders()?.sourcePlease open Telegram to view this post
VIEW IN TELEGRAM
🗞 Дайджест новостей для iOS разработчиков за январь
Небольшие но важные изменения к которым нужно подготовиться:
🔵 iOS 26.3 beta 2. Apple выкатили beta версии 26.3, релиз совсем скоро, самое время прогнать тесты
🔵 App Store комплаенс — важные дедлайны
🔴 Age Rating: до 31 января 2026. Рейтинги приложений автоматически “пересчитали” под новую систему, но вам нужно ответить на обновлённые вопросы в App Store Connect до 31.01.2026, иначе можно словить блок при отправке апдейтов
🔴 Техас: возраст, согласия, PermissionKit. С 1 января 2026 для новых Apple Accounts в Техасе включаются требования по age assurance и parental consent (до 18 лет) — Apple даёт API для получения возрастной категории.
🔴 EU: новая модель условий и UX установки
🔴 Корея Sign in with Apple: новое требование (с 1 января 2026). При регистрации/обновлении Services ID нужно указывать endpoint для server-to-server нотификаций
🔵 Swift 6.2.3 вышел в декабре, а в январе уже доступны снапшоты ветки release/6.3. В 6.2 заметно прокачали “approachable concurrency” (включая режимы изоляции), добавили опции для более строгой memory safety, ускорили сборки проектов с макросами (prebuilt swift-syntax) и продолжают развивать экосистему библиотек/тестов
Небольшие но важные изменения к которым нужно подготовиться:
Please open Telegram to view this post
VIEW IN TELEGRAM
🈸 StoreKit 2: как давать доступ к premium-фичам (и не сломать уровни подписки)
Не часто приходится работать с in-app-ми и это то место, в котором не хочется допускать ошибки. Тут и репутационные и финансовые риски. Особенно сложно работать с нескольими уровнями подписок: как только вы добавляете несколько тарифов (например, личный / семкйный + месяц / год), появляются типичные боли:
🔵 Приложение не понимает “какой план активен”, когда есть overlap при апгрейде/даунгрейде
🔵 UI не может честно показать “что сейчас” и “на что продлится”
🔵 Транзакции прилетают повторно / ennoscriptment “откатывается” после рестарта
Подход из статьи: “всегда выбираем самый высокий tier”
1) Группы подписок + уровни (Level of Service)
Apple использует “Subnoscription Level” (lower number = *higher tier*) для логики апгрейдов/даунгрейдов и того, какая подписка должна считаться активной
В примере:
🟢 Family = level 1 (выше)
🟢 Individual = level 2 (ниже)
🟢 Monthly и Yearly одного тира должны иметь одинаковый level, чтобы это был тот же tier, другая периодичность.
2) Модель тиров в коде
Делаем enum
3) Вычисляем текущий доступ по status’ам
Фильтруем
4) Trust only verified
Только
5) Обязательно finish + наблюдаем апдейты
🟢 Каждую verified транзакцию нужно
🟢 На старте проверяем
🟢 Держим живым listener на
6) UI: SubnoscriptionStoreView + статус рядом
В статье используют
Эмпирическое правило для подписок
🟢 Ennoscriptment = verified transaction + правильно настроенный tier
🟢 Тарифы = данные (ASC/StoreKit config), код должен лишь корректно их интерпретировать
🟢 UI всегда показывает “effective tier”, а не последний купленный productID
Не часто приходится работать с in-app-ми и это то место, в котором не хочется допускать ошибки. Тут и репутационные и финансовые риски. Особенно сложно работать с нескольими уровнями подписок: как только вы добавляете несколько тарифов (например, личный / семкйный + месяц / год), появляются типичные боли:
Подход из статьи: “всегда выбираем самый высокий tier”
1) Группы подписок + уровни (Level of Service)
Apple использует “Subnoscription Level” (lower number = *higher tier*) для логики апгрейдов/даунгрейдов и того, какая подписка должна считаться активной
В примере:
2) Модель тиров в коде
Делаем enum
PassStatus (notSubscribed / individual / family) и маппим productID → tier, чтобы интерпретировать статусы StoreKit3) Вычисляем текущий доступ по status’ам
Фильтруем
statuses до .subscribed и выбираем max tier (чтобы Family “перебивал” Individual при overlap)4) Trust only verified
Только
.verified транзакции считаем ennoscriptment’ом. Если verification не прошёл — считаем “нет подписки”.5) Обязательно finish + наблюдаем апдейты
finish(), иначе StoreKit может принести её сноваTransaction.unfinished (после крэша/сети)Transaction.updates для мгновенного обновления UI6) UI: SubnoscriptionStoreView + статус рядом
В статье используют
SubnoscriptionStoreView(groupID:), а текущий tier и “renews to …” строят из renewalInfo.Эмпирическое правило для подписок
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Немного базы в пятницу, статья про жесты в SwiftUI.
Кейс один экран — несколько интеракций
Как только на элементе появляются drag + rotate + long press + tap — SwiftUI быстро начинает угадывать, какой жест вы имели в виду и не всегда у него это выходит успешно:
Все это создает негативный UX
.gesture(...) и надеяться... На что-то обычно заканчивается тем, что один жест побеждает всегда, а второй почти не срабатывает.Три базовых композиции жестов в SwiftUI:
Кейс: long press → drag
Используем
LongPressGesture(...).sequenced(before: DragGesture())Идея:
@GestureState обновляется через .updating(), а drag-translation читаем в .onChanged() на втором этапеКейс: drag + rotate
DragGesture().simultaneously(with: RotateGesture()).onChanged()Кейс: tap vs long press
ExclusiveGesture(TapGesture(), LongPressGesture(minimumDuration: 1.0))Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Я вам несколько раз рассказывал про Skip и о своих надеждах и сомнениях по поводу этого инструмента и пришли новости. Платно получать лок на вендора желающих достаточно не оказалось, но наработки пригодились Apple рабочей группе по Android.
📱 Проблема: cross-platform “без компромиссов” всегда упирался в доверие
Многие команды хотят Swift/SwiftUI → Android, но боятся строить стратегию на маленьком закрытом платном туле: “а если завтра rug pull / покупка / закрытие?”. Skip прямо называет этот страх ключевым барьером adoption.
Начиная с Skip 1.7:
Моя оценка Skip в 2026:
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔6👍3❤1🔥1
iOS 26 принёс Liquid Glass как новый визуальный слой системы. Первое время Apple дала “костыль” — compatibility mode, чтобы старый UI не «поплыл» сразу после перекомпиляции. Но ключевое слово тут — на первое время.
Когда перестаёт работать режим совместимости?
Сегодня (Xcode 26 / iOS 26) можно отложить новый дизайн через
Info.plist ключ UIDesignRequiresCompatibility (UI Design Requires Compatibility). Donny Wals прямо пишет, что Apple планирует убрать эту опцию в следующем мажорном Xcode, и поэтому Xcode 27 вероятно сделает Liquid Glass обязательнымДополнительно, на форумах Apple в обсуждениях этого ключа фигурирует предупреждение из документации:
Temporarily use this key while reviewing and refining your app’s UI for the design in the latest SDKs
То есть ставка на “оставим compat mode навсегда” — плохой план.
И ещё момент: compatibility mode уже может ломать поведение контролов (пример — баг с
UISegmentedControl, который проявляется именно при включённом UIDesignRequiresCompatibility)Стратегия миграции без боли:
UIDesignRequiresCompatibility)Самый простой вариант — две
Info.plist: Info-Dev.plist и Info-Release.plist, и переключение в Build Settings.Начинайте не с карточек/экраников, а с того, что пользователь видит всегда:
Цель: чтобы приложение выглядело органично *в рамках нового system look* — даже если ваш контент ещё не идеален.
Liquid Glass любит:
А ломает:
Правило: переходите на системные семантические цвета/материалы там, где можно, а кастом оставляйте для контента.
Accessibility — обязательный прогон
Иначе вы сделаете красиво, но сломаете читаемость для части пользователей.
1. Принять Liquid Glass как новый baseline
2. Сделать свои компоненты
⚠️ Подходит только если у вас продукт, где дизайн — ключевой дифференциатор, и есть ресурс на поддержку.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
Большой релиз инструмента, который мы активно используем у себя внутри для работы с приложениями.
Когда у вас сотни/тысячи модулей, вы начинаете страдать от обвязки:
.xcodeproj/.xcworkspace становится медленнойРешение: Geko
Geko — CLI-утилита для управления dev-инфраструктурой Xcode-проектов: DSL на Swift для описания структуры, генерация проектов и встроенная система кэширования.
Что есть из коробки:
.xcodeproj/.xcworkspace даже для тысяч модулей⚡️ Кэш: топ фича из коробки:
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11