tgindex
EasySwift iOS🍏

EasySwift iOS🍏

Статистика

Все самое интересное в мире iOS разработки 🧑🏻‍💻 Предложить статью или новость: @EasySwiftBot По всем вопросам обращаться к @itereznikov

Последний пост
14 авг.
Последнее чтение
18:15
Постов за неделю
4
Всего постов
22
Тип
открытый
Язык
русский
Категория
Новости и СМИ
В каталоге с
13 авг.
Подписчики
2 845
−2 за 3 дн.
Сутки
−2
−0,07%
Неделя
 
Месяц
 
Просмотров на пост
628
22 постов
Вовлечённость
22,1%
к подписчикам
Постов в день
0,6
всего 22
Упоминаний
0
каналов
Охват размещения
оценка
1/24сутки в ленте
355
1/48двое суток
406
1/72трое суток
438

Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.

Посты

  • видео или голосовое, без подписи

  • Building Testable SwiftData Applications 👀 В статье - как правильно тестировать SwiftData в iOS проектах, и главный акцент делает не на проверке самого фреймворка, а на защите бизнес логики. Для обычных юнит тестов лучше брать in-memory store, чтобы тесты были изолированными, быстрыми и не зависели друг от друга. ⚠️ В статье хорошо показано, какие тесты почти не дают пользы: например, когда вы просто проверяете, что модель сохранилась и снова прочиталась из базы. Гораздо ценнее тестировать реальные правила приложения - запрет одинаковых названий бюджета, корректный расчёт расходов, остатка и других важных значений. ⚙️ Отдельно автор показывает, что сложную логику лучше выносить из View в отдельные типы. Тогда код проще поддерживать, а тесты писать легче. В конце есть интересная мысль про ResultsObserver в iOS 27: он помогает наблюдать изменения SwiftData вне SwiftUI и тестировать такие сценарии без лишней возни с интерфейсом. 😊 Признавайтесь - тестируете SwiftData?

  • Picture-in-Picture в iOS: от запуска до переключения контента 🔍 Статья - практичный гайд по PiP на iOS. Автор показывает, как запустить системное «плавающее окно», настроить жизненный цикл и переключать контент без разрывов. Главный посыл: PiP - сквозной системный механизм, который живёт в отдельном окне и требует правильной подготовки. Что обязательно проверить: ➡️ AVAudioSession настроен на .playback/.moviePlayback и активен - без этого PiP не стартует ➡️ В Capabilities включён Background Modes -> Audio, AirPlay, and Picture in Picture. ➡️ AVPictureInPictureController хранится в сильной ссылке, иначе ARC удалит его до отрисовки Как жить с PiP в приложении: ➡️ Делегат нужен для восстановления интерфейса и очистки после остановки. ➡️ События управления (пауза/перемотка) не приходят через делегат. На iOS 18+ используйте AVMetrics, на более старых - KVO/Combine по timeControlStatus у AVPlayer. ➡️ Переключение видео без закрытия PiP: либо replaceCurrentItem(with:) у AVPlayer, либо, если пересоздаёте плеер, обновите contentSource у контроллера.

  • Building a reusable API client with URLSession in Swift 🔍 Очередной взгляд на то, как собрать лёгкий API‑клиент на базе URLSession и async/await. Выделяются общие шаги любых запросов, а именно: построение URLRequest, выполнение через URLSession, проверка HTTP ответа и декодирование JSON - и предлагает вынести их в одно место (APIClient) чтобы не дублировать код по проекту. Приводятся компактные типы: ➡️ Endpoint с путём ➡️ методом и заголовками ➡️ небольшая обработка ошибок (invalidResponse, invalidStatusCode) ➡️ методы для сборки запроса и отправки ➡️ пример декодирования модели 🖥 Можно еще выделить в качестве полезных советов: ➡️ конфигурация URLSession через URLSessionConfiguration для таймаутов и кэша ➡️ передача сессии в клиент для тестируемости ➡️ корректная проверка HTTPURLResponse (чтобы 404/500 не прошли незамеченными) ➡️ встроенная поддержка отмены через Swift concurrency (task отменяет запрос). В целом, можно взять как стартовую точку и расширить авторизацией, логированием и обработкой ошибок по бизнес‑логике.

  • An Even Closer Look at Protocols and Global Actors ❓ Как лучше задавать изоляцию @MainActor для протоколов в Swift — всей протоколу, отдельным требованиям или вовсе не ставить атрибут? ℹ️ На примере протокола для показа ошибок автор сравнивает «whole‑protocol» (удобно и сокращает код, но раньше мешало конформить акторы) и «per‑requirement» (более гибко, явнее поведение). ⚙️ Не вешайте @MainActor автоматически - сначала подумайте, где реально нужна синхронная работа с UI. Для внутренних API удобно использовать per‑requirement изоляцию, а для публичных или простых случаев можно сделать протокол не‑изолированным и перенести @MainActor на конкретные реализации. Особое внимание уделите параметрам (например, колбэкам) - им может понадобиться свой атрибут @MainActor или объявление как Sendable.

  • 5 авг.641424

    Splitting Large SwiftUI Views in the Apple's way 🔍 Интересная статья, где рассказывают, что для производительности в SwiftUI важнее выделять отдельные структуры View с узкими входными данными, чем разбивать большой body на вычисляемые переменные или вспомогательные функции с @ViewBuilder. Когда меняется состояние, SwiftUI пересчитывает body самого внутреннего типа View, поэтому все вычисляемые поля внутри того же struct пересчитаются вместе - отдельный struct даёт собственную границу инвалидизации и может быть пропущен, если его входы не изменились. ❓ Что можно сделать (на примерах из статьи): ➡️ заменить private var section: some View на private struct SectionView ➡️ передавать только нужные данные (Bool, Double, модель) ➡️ выносить тяжёлые части интерфейса - карты, карточки завершения, сложные списки - в отдельные типы. ⚙️ @ViewBuilder остаётся полезным для локальной условной структуры (if/switch), он даёт читаемость и структурную идентичность веток, но он не создаёт новую границу инвалидизации и не решит проблемы с лишними пересчётами или потерей состояния при переключении веток. 🖥 Короткий чеклист для ревью кода: ➡️ если вычисляемое поле зависит от часто меняющегося state - выносить в отдельный View ➡️ не пытаться «симулировать» сплит через @ViewBuilder или вспомогательные модификаторы ➡️ предпочитать modifier(value ? a : b) вместо if-веток для одного view

  • 3 авг.643413

    Liquid Glass: A Field Guide to UIKit Compatibility Pitfalls 🖥 Если все еще не мигрировали на Liquid Glass на UIKit - статья для вас: практические проблемы адаптации UIKit на iOS 26, замеченные автором в реальном проект. ❓ Главные кейсы - кнопки навигации, таббар и взаимодействие с WKWebView. Для UIBarButtonItem с customView на iOS 26 наблюдались искажение размеров и исчезновение цветов: решение - полностью «изолировать» вью с явными constrain (ширина, высота и центр) или заменить UIKit вью на SwiftUI через UIHostingController; это в большинстве случаев восстанавливало и размеры, и цвет. 🔍 Немного про баги с новым API бейджей (иногда не обновляется - простой трюк: временно убрать и вернуть customView) и переносом порядка rightBarButtonItems (иногда помогает DispatchQueue.main.async или лучше - trailingItemGroups). ⚙️ Про UITabBarController и WKWebView: если вы динамически перестраиваете таббар во время закрытия модального контроллера, это может ломать интерфейс - ждущая окончания анимации dismiss решает проблему. При встраивании WKWebView стоит обязательно использовать viewport-fit=cover и env(safe-area-inset-*) в CSS, иначе контент может оказаться под таббаром (особенно при position: fixed). ℹ️ Наконец, есть баги без простого решения (например, смещение Stepper при появлении клавиатуры), поэтому автор советует тестировать на каждой поддерживаемой версии iOS и по возможности следовать HIG - чем дальше вы уходитe от стандартов, тем больше вероятность странных ошибок.

  • Saving lives with enums ℹ️ Статья показывает простую, но часто забываемую практику при работе с enum в Swift - не прятать случаи под default и не полагаться на прямое сравнение (==). Автор объясняет, что при добавлении новых кейсов компилятор не предупредит об уязвимых местах, если вы везде использовали default или ==. Это может привести к логическим ошибкам - в примере с мороженым человек с аллергией может получить опасный продукт. ✔️ Как одно из решений: делать «исчерпывающие» switch - явно перечислять все кейсы вместо default и переносить проверки в вычисляемые свойства или функции с exhaustive-switch. Тогда при добавлении нового кейса компилятор выдаст ошибку и вы вынуждены будете явно решить, как новый кейс обрабатывать. Это чуть более многословно, но даёт безопасность и явность. Можно также добавить правило в линтер, но это за пределами этой статьи. ⚠️ Если сомневаетесь - откажитесь от default и от частых == для enum, особенно если enum используется в логике принятия решений. Лучше перестраховаться, чем потом получить баг в проде…

  • 29 июл.6851118

    Сейчас будет горячо: нагрев iOS-устройств как продуктовая метрика Зачем собирать thermal‑метрику в iOS и как? (Картинка передает суть 🙂) 🔴 Вместо попыток мерить температуру в градусах автор предлагает использовать ProcessInfo.ThermalState - системную оценку теплового давления с четырьмя состояниями (nominal, fair, serious, critical). ThermalState нельзя перевести в градусы, но оно уже нормализовано между моделями и даёт понятный сигнал, когда система начинает троттлить I/O, снижать FPS или отключать периферию. 🔍 Читайте thermalState один раз перед регистрацией наблюдателя и логируйте изменения через thermalStateDidChangeNotification. А также отправляйте события в аналитику с контекстом (модель, экран, уровень батареи, зарядка, длительность сессии и т.д.). Это дешёвая в реализации метрика (одно свойство + нотификация + событие), но даёт полезные дашборды: ➡️ распределение по состояниям ➡️ по моделям ➡️ по экранам ➡️ время до first serious ➡️ сравнение версий ➡️ связь с Crash Rate и FPS. 🔥 На её основе можно приоритизировать оптимизации, включать адаптацию под конкретные устройства и реализовать реактивную деградацию в рантайме. let state = ProcessInfo.processInfo.thermalState NotificationCenter.default.addObserver( forName: ProcessInfo.thermalStateDidChangeNotification, object: nil, queue: .main ) { _ in let newState = ProcessInfo.processInfo.thermalState Analytics.track(thermalState: newState) }

  • Introducing the Safari MCP server for web developers ℹ️ Safari MCP‑сервер в бета‑версии Safari 27 и Safari Technology Preview 247 - это реализaция Model Context Protocol, которая позволяет LLM‑инструментам подключаться к окну Safari и получать реальную информацию о странице: DOM, сетевые запросы, скриншоты и консольные логи. Для iOS‑разработчика практическая польза такая: меньше ручных прогонов сценариев, быстрее проверка экранов после изменений, удобнее искать расхождения между ожидаемым и фактическим состоянием интерфейса, проще ловить проблемы с доступностью и состояниями форм. ❓ Можно использовать для некоторых кейсов: ➡️ упрощённая отладка без постоянного переключения между окнами ➡️ проверка совместимости в Safari ➡️ анализ производительности (navigation timing, загрузки ресурсов) ➡️ базовая проверка доступности ➡️ верификация состояний интерфейса (формы, потоки оформления заказа). 🖥 Запуск прост: установить нужную версию Safari, включить веб‑функции и удалённую автоматизацию, добавить mcp‑сервер в конфиг агента или выполнить одну из команд для Claude/Codex. MCP работает локально и не отправляет данные в Apple - дальнейшая судьба логов зависит от выбранного агента, поэтому используйте только доверенные инструменты.

  • How did Apple cut launch time by 30% in iOS 27? 🔼 Время запуска приложения - одна из самых важный метрик, которую многие не оптимизируют. Есть три вида запуска - cold, warm, resume. А сам процесс делится на до‑main (dyld, mmap, фиксация символов, статические инициализаторы) и после‑main (создание UIApplication, сцены, рендер первого кадра). 🔍 В статье автор показывает практическое сравнение трейсов запуска iOS 26 и iOS 27 с инструментами Xcode: App Launch и flamegraph. На его тестах iOS 27 даёт заметное ускорение - примерно 20–23% в примерах - в основном за счёт сокращения времени pre‑main (быстрее строятся кложуры, быстрее применяются fixups и выполняются статические инициализаторы). Часть улучшений объясняется параллелизацией и предзагрузкой данных на уровне системы. 👍 Выводы просты и применимы: профилируйте запуск (App Launch, фильтр на main-поток, скрывайте системные библиотеки), уменьшайте вес pre‑main (меньше динамических библиотек и тяжёлых статических инициализаторов) и минимизируйте работу до первого кадра. Системные оптимизации полезны, но основная ответственность за быстрый старт - на разработчике и архитектуре приложения.

  • Swift 6.2 против вашего оптимизатора: разбираемся с InlineArray, Span и strict memory safety на замерах ❓ Это не ещё одна сухая статья про ARC - автор взял три нововведения Swift 6.2, связанных с памятью, и проверил их «в бою»: замеры в release‑сборке, анализ ассемблера и SIL, перцентили вместо среднего, и честные проверки на оптимизатор. ❗️ Главная мысль: часто оптимизатор уже делает то, что обещают новые фичи, поэтому выигрыш встречается не везде, и важно понимать когда именно он реальный. 🖥 Что полезно помнить по фичам: InlineArray - настоящее преимущество там, где маленький фиксированный буфер лежит внутри структуры и её часто копируют; там вы избегаете retain/COW и получаете заметный выигрыш. Для локальных массивов же компилятор чаще сам помещает Array на стек, так что InlineArray не даёт чуда. 🔍 Span/MutableSpan - безопасная заменa небезопасных указателей: в горячих циклах код часто эквивалентен UnsafeBufferPointer, но Span избегает мостов к NSArray и даёт более предсказуемые хвосты; MutableSpan полезен при мутациях, когда надо избежать COW. ℹ️ В итоге: не гонитесь за «всегда быстрее» - используйте эти инструменты там, где они дают ясное семантическое преимущество, а не ради общих страховок про производительность.

  • User Diagnostics Reports: Solving app bugs faster with AI Agents ⚙️ Diagnostics — открытый инструмент для встроенной генерации диагностических отчётов, которые пользователи могут прикреплять к письму в поддержку. Отчёт создаёт подробный HTML с системной информацией (версия ОС и приложения, язык, свободное место, тип устройства), сессиями и логами, где есть фильтрация и выделение ошибок. ⚠️ Особенность — «умные подсказки»: библиотека может анализировать строки логов и добавлять готовые выводы для поддержки, например обнаружение проблемы со Stage Manager. Отчёты теперь содержат встраиваемый JSON, что позволяет автоматизировать разбор, отправлять данные напрямую в багтрекер или использовать агенты для анализа. Также можно сразу генерировать JSON вместо HTML через API (DiagnosticsReporter.create(format: .json)), что удобно для интеграций и AI‑оптимизированных рабочих процессов. 👀 Сама либа open source. Так что всегда можно посмотреть, что внутри. Выглядит интересно, советую попробовать на своих пет проектах.

  • Что такое View в SwiftUI 👀 SwiftUI.View — это протокол с ассоциированным типом Body, то есть каждое представление должно объявить, какого типа его body. Это важно: View — не «готовый UI-элемент», а описание интерфейса. Поэтому тип body определяет, что именно будет отображаться, а само представление — легковесная декларация, а не непосредственный объект UIKit/AppKit. ⚙️ Проблема с ветвлениями и some View решается не самим some, а @ViewBuilder. some View требует один конкретный тип, но ViewBuilder собирает разные ветви и несколько дочерних представлений в единый результирующий тип (например, _ConditionalContent или TupleView). Благодаря этому в body можно писать if/else или несколько подряд view — под капотом всё превращается в единый тип, который и возвращается как some View.

  • The hidden cost of unstable SwiftUI environment defaults Warning Storing a class type in '@Entry var logger' may invalidate dependents on every update because the default value is reallocated on every access. Initialize the default value elsewhere and reference it from the '@Entry' declaration. ⚠️ Новая подсказка компилятора в Xcode 27 — предупреждение для @Entry, когда в качестве значения по умолчанию создаётся экземпляр класса прямо в объявлении. При отсутствии внедрённого значения среда каждый раз вычисляет getter и заново создаёт объект; поскольку классы сравниваются по ссылке, SwiftUI считает значение изменившимся и повторно рендерит зависимые представления, вызывая лишние обновления. ❓ Если у вас в EnvironmentValues по умолчанию создаются объекты, это может привести к неожиданным перерасчётам представлений. Простые решения - вынести экземпляр в стабильное хранилище или сделать значение опциональным и явно внедрять в App, чтобы избежать молчаливых ошибок конфигурации. private let defaultLogger = AppLogger() extension EnvironmentValues { @Entry var logger = defaultLogger }

  • Defer in Swift explained with Code Examples 👍 В очередной раз база про ключевое слово defer в Swift и напоминание, почему его стоит чаще использовать — особенно после появления поддержки await внутри defer в Swift 6.4. ❓ Главная идея: defer гарантирует выполнение очистки при выходе из области видимости, причём несколько defer выполняются в обратном порядке; в Swift 6.4 такие блоки могут выполнять асинхронную работу и дождаться её завершения перед возвратом из функции. 👀 Типичные применения: закрыть файл или вызвать комплишен, чтобы не дублировать код на всех путях выхода. В статье показаны примеры: простой defer с печатью, несколько defer - они выполняются как стек, defer для закрытия FileHandle и новый вариант с await внутри defer для безопасного асинхронного закрытия. Автор предупреждает: нельзя заменять это на Task - тогда очистка станет неструктурной и может закончиться позже, чем функция вернёт управление; также defer не глушит отмену задачи (Task.isCancelled остаётся доступен).

  • iOS27: CADisplayLink for UIWindowScene ❓ Timer или CADisplayLink? Автор в этой статье объясняет, в чём фундаментальная разница: Timer опирается на интервалы времени, CADisplayLink - на границы кадров экрана. Для визуальных задач, где важна плавность и синхронизация с частотой обновления, CADisplayLink даёт более точную и естественную основу. Timer по-прежнему проще и дешевле для задач, где важен не каждый кадр - например, обратный отсчёт или периодический сетевой опрос. ❗️ Отмечаются типичные ошибки при работе с CADisplayLink: ➡️ не заменяет таймер во всех случаях ➡️ легко тратить ресурсы при частых колбэках ➡️ нужно корректно инвалидировать и учитывать режимы run loop 🆕 Для iOS 27 подчёркивается новое направление: сцено-ориентированное создание display link, что улучшает владение, поведение в многоконечных приложениях и позволяет логичнее привязывать визуальную работу к конкретной UIWindowScene

  • 9 июл.706712

    Как сломать Swift Concurrency 👀 Основная идея: задачи выполняются на кооперативном пуле потоков, количество потоков ограничено ядрами CPU, и любые блокирующие вызовы или бесконечные синхронные циклы захватывают эти потоки и мешают выполнению других задач, что приводит к зависаниям или дедлокам - особенно на слабых устройствах или CI с 1–2 ядрами. ❗️ Примеры и симптомы: ➡️ запуск sync внутри Task забирает поток пула и тормозит другие задачи ➡️ взаимоблокировки между очередями или на одной очереди приводят к плавающим дедлокам ➡️ блокировка главного потока через sync ломает UI и может вызвать убийство приложения ➡️ плотный CPU‑цикл без await удерживает поток ✔️ Отсюда и рекомендации: ➡️ не делать долгие синхронные операции внутри Task ➡️ оборачивать callback в continuations (withCheckedContinuation) ➡️ выносить тяжёлую работу в отдельные исполнители или очереди ➡️ вставлять await Task.yield() в длинные циклы ➡️ явно помечать публичные синхронные блокирующие функции ➡️ тестировать на слабых устройствах

  • Memberwise Initializer in Swift explained with Code Examples ➡️ Swift автоматически генерирует memberwise‑инициализатор для struct - он принимает значения для всех хранимых свойств, что экономит шаблонный код. Свойства с дефолтными значениями становятся параметрами с значениями по умолчанию, так что часто можно создавать модели без ручных init. 🆕 В Swift 6.4 поправили поведение для приватных свойств с начальным значением: такие менее доступные поля теперь исключаются из сгенерированного инициализатора, поэтому приватный backing‑state не делает весь инициализатор приватным. Это убирает ненужный бойлерплейт и логично - приватное поле с дефолтом остаётся внутренней деталью. ❗️ Важные нюансы: приватные свойства без значения по‑прежнему включаются в инициализатор (их нужно инициализировать вручную), а memberwise‑инициализаторы генерируются максимум с internal‑доступом, так что для public struct всё равно нужен явный public init.

  • Using Claude with Apple Foundation Models 🆕 Теперь тот же API LanguageModelSession, что работал с локальными моделями, поддерживает и серверные модели через протокол LanguageModel. Anthropic выпустил пакет ClaudeForFoundationModels, который делает Claude «вставной» моделью: ровно тот же код для сессий, генерации через @Generable, стриминга и вызова инструментов. Это простая интеграция — достаточно добавить пакет и создать ClaudeLanguageModel с ключом, затем передать его в LanguageModelSession. ⚙️ Потоковая генерация поддерживается (streamResponse) — это важно для UX с серверном моделью. Пакет мапит ошибки Claude на LanguageModelError, есть поддержка server-side tools (поиск, исполнение кода) у модели. ❗️ Минусы: iOS 27 / Xcode 27 бета сейчас обязательны, и пока App Attest ещё не доступен; нужно учитывать биллинг Anthropic и защищённую передачу ключей. Для поддержки старых iOS можно посмотреть AnyLanguageModel от Hugging Face.