Мобильный трудоголик – Telegram
Мобильный трудоголик
1.44K subscribers
64 photos
10 videos
289 links
👨‍💻 Пишу простым языком об iOS разработке на Swift и мобильной разработке в целом.
🔹 Вошел в IT задолго до того как это стало мейнстримом.
---
‍Обо мне: https://news.1rj.ru/str/hardworkerIT/3
Чат: @hardworkerChatIT
Канал про разработку и жизнь в ИТ: @itDenisov
Download Telegram
🔨 Xcodebuild, Swift Build и Swift-Build: как устроен конвейер сборки в Swift.

Когда вы запускаете сборку проекта, под капотом запускается не один инструмент, а целый конвейер. Многие разработчики воспринимают сборку как нечто монолитное, но в современной экосистеме Swift она разделена на четкие слои абстракции. Понимание того, как xcodebuild, swift build и swift-build взаимодействуют - это ключ к эффективной отладке сложных проблем со сборкой, созданию кастомных инструментов и глубокому пониманию того, как ваши проекты превращаются в исполняемый код.


Абстрактный сердцевинный движок: swift-build как единый планировщик задач:

В основе всего лежит swift-build - низкоуровневый движок, построенный на llbuild. Его задача - не понимать Swift, Xcode-проекты или манифесты пакетов. Его задача - эффективно планировать и исполнять граф зависимостей задач. Он работает с абстрактным промежуточным представлением проекта - PIF (Project Intermediate Format). PIF - это, по сути, универсальный язык, на котором можно описать любую задачу сборки: компиляцию .swift файла, линковку библиотеки, копирование ресурсов. swift-build получает этот граф задач и решает, что, когда и как выполнять, оптимизируя параллелизацию и инкрементальные сборки.


Трансляторы - как swift build и xcodebuild говорят с движком:

Здесь начинается специализация. Ни swift build (система сборки Swift Package Manager), ни xcodebuild не компилируют код сами. Они - трансляторы или фронтенды.

🔵swift build (SwiftPM): его мир - это Package.swift. Он парсит манимуфест, анализирует зависимости, разрешает версии и строит граф таргетов специфичный для пакетов. Затем он транслирует этот граф в универсальный PIF и передает его на выполнение движку swift-build с флагом --build-system=swiftbuild.

🔵xcodebuild: его вселенная - это .xcodeproj с кучей настроек (Build Settings), схем (Schemes) и конфигураций. Он считывает этот комплексный проект, разрешает все переменные, обрабатывает зависимости (включая те же Swift-пакеты через XCFrameworks) и транслирует всю эту информацию в тот же самый PIF. Затем он передает PIF тому же самому движку swift-build.


Ключевое преимущество - разделение ответственности и совместимость:

Польза от такого гениального решения:

🔵Единый кэш и инкрементальность: независимо от того, собираете ли вы пакет через SwiftPM или проект через Xcode, движок swift-build один. Это значит, что кэш объектов (DerivedData) и механизм инкрементальной сборки унифицированы и работают согласованно.

🔵Снижение сложности: движку сборки не нужно знать сотни Build Settings Xcode. Ему говорят: «скомпилируй этот файл с этими флагами». А xcodebuild уже сам разбирается, как из настроек SWIFT_OPTIMIZATION_LEVEL и OTHER_SWIFT_FLAGS сформировать итоговый вызов компилятора.

🔵Возможность для сторонних инструментов: такие проекты, как Tuist или XcodeGen, используют эту же схему. Они не изобретают свой компилятор. Они генерируют .xcodeproj (или даже сразу PIF), а затем используют стандартный xcodebuild или напрямую swift-build для сборки. Это обеспечивает стабильность и совместимость.


Где прячется swiftc? Роль компилятора в этой цепочке:

Компилятор swiftc - это просто еще одна задача в графе, который строит движок swift-build. Когда движок видит в PIF задачу типа «скомпилировать Swift-файл», он вызывает swiftc с конкретным набором аргументов, которые были подготовлены для него фронтендом (xcodebuild или swift build). swiftc не имеет состояния между вызовами и ничего не знает о проекте в целом, он просто компилирует то, что ему передали.


💡 Вывод:

Сборка в экосистеме Swift - это не монолит, а пайплайн с четкими интерфейсами: фронтенд (xcodebuild/swift build) отвечает за понимание формата проекта и генерацию абстрактного плана, а бэкенд (swift-build) - за оптимальное исполнение этого плана через вызов низкоуровневых инструментов вроде swiftc.

Такое разделение позволяет Apple независимо развивать удобные инструменты для разработчиков (Xcode, SwiftPM) и высокопроизводительный движок сборки.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
1710👍4🔥1🙏1
🔢 MetricKit: мониторинг производительности iOS-приложений на проде.

В iOS-разработке есть один недооцененный инструмент, который дает доступ к метрикам, обычно скрытым от нас. Речь о MetricKit - фреймворке Apple для сбора системной диагностики с устройств пользователей. Это не просто альтернатива краш-репортам, а принципиально другой уровень понимания того, как приложение ведет себя в реальных условиях.

Стандартные инструменты показывают, что упало. MetricKit показывает, почему это произошло. Не только краши, но и зависания, энергопотребление, временя запуска и десятком других, системных параметров. Это данные, которые ОС собирает сама, без участия пользователя и с минимальным влиянием на производительность.


Особенности:

MetricKit раскрывает три слоя проблем, которые иначе остаются невидимыми:

🔵Системные завершения приложения: вместо общего «приложение закрыто» вы получаете конкретную причину: нехватка памяти, превышение лимита CPU, Out Of Memory (OOM) или фоновая активность. Это позволяет отличать баги от системных ограничений.

🔵Ресурсные метрики в контексте: энергопотребление разбивается по компонентам (CPU, дисплей, сеть), I/O операции показываются с объемами и временем выполнения, а зависания детектируются автоматически с полным стек-трейсом.

🔵Агрегированные данные для трендов: MetricKit не сыплет событиями, он присылает агрегированные отчеты раз в 24 часа. Это идеально для анализа трендов: как изменилось время запуска после обновления, выросло ли энергопотребление новой фичи, снизилось ли количество OOM после оптимизации.


🔗 Ссылка на подробную статью


💡 Вывод:

MetricKit меняет подход к качеству приложений с реактивного на проактивный. Вместо того чтобы ждать жалоб из App Store, вы видите проблемы до того, как они станут массовыми. Это инструмент для команд, которые хотят не просто исправлять баги, а понимать фундаментальные причины проблем производительности.

Главное преимущество - объективность. Вы получаете не субъективные оценки, а точные системные метрики. Это позволяет принимать архитектурные решения на основе данных, а не предположений. Для серьезных проектов внедрение MetricKit должно быть не опцией, а стандартом разработки.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1610🔥43🤔1🙏1🤝1
Forwarded from Кот Денисова
👨‍💻 Инфляция должностей: как компании нас обманывают.

Инфляция должностей в ИТ - это когда разработчикам дают громкие названия позиций без реального роста ответственности и зарплаты. Например:

🔹Джуниора называют миддлом.
🔹Миддла повышают до сеньора.
🔹Но зарплата и реальные обязанности остаются прежними.


Почему компании так делают:

В аутсорсе это была стандартная практика:

🔹Джуниору с зарплатой 100к в год дают звание миддл.
🔹Продают клиенту как миддла за 200к.
🔹Разницу в 100к компания забирает себе.


Такая практика вредит всем:

🔹Разработчикам: они не растут профессионально, довольствуясь красивым титулом.
🔹Компаниям: их репутация падает, когда обман раскрывается.
🔹Рынку: настоящие специалисты теряются среди раздутых резюме.


Что с этим делать:

🔹Реально оценивать свой уровень, а не гнаться за громкими званиями.
🔹При смене работы требовать не только высокий грейд, но и соответствующие обязанности и зарплату.
🔹Не верить красивым обещаниям быстрого карьерного роста.


💡 Вывод:

Инфляция должностей создает системные проблемы для всей ИТ-отрасли. Когда компании массово присваивают завышенные звания без реального роста компетенций, это девальвирует ценность настоящих специалистов и затрудняет найм.

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


➡️ Кот Денисова
Please open Telegram to view this post
VIEW IN TELEGRAM
👍176🤯3🔥1🙏1
🎄 Друзья, с наступающим Новым годом!

С мая я каждый день старался радовать вас полезными постами и искренне надеюсь, что они принесли вам не только новые знания, но и реальный профессиональный рост.

Я очень благодарен за ваше внимание и активность. Сейчас я ухожу на заслуженные выходные, но в январе вернусь с новыми идеями.


Желаю вам в 2026 году:

🎉 Освоить технологии, которые сделают вас ценнее на рынке.

🎉 Найти проекты, от которых горят глаза.

🎉 Получать не только опыт, но и достойное вознаграждение.

🎉 И никогда не переставать удивляться возможностям кода.


Пусть новый год будет полон открытий и достижений!
С Новым годом! 🎉
Please open Telegram to view this post
VIEW IN TELEGRAM
39👍21🙏4🔥1👏1
🔨 Не все краши одинаковы. Системный подход к отладке падений iOS-приложений.

Всем привет! Сегодня разберем системный подход к работе с крашами iOS-приложений. Частая ошибка - пытаться сразу лезть в код, не поняв, какой именно сбой произошел. Это как лечить температуру, не зная, грипп это или воспаление легких. Каждый тип краша - это сигнал от системы, который указывает на определенный класс проблем. Когда приложение падает, операционная система отправляет сигнал (signal) о причине прекращения работы. Этот сигнал - ключ к быстрой диагностике.


Шесть основных сигналов и методы их исправления:


🔵Сигнал 1: EXC_BAD_ACCESS:

Приложение попыталось обратиться к участку памяти, который уже освобожден или никогда не принадлежал ему. Причиной могут быть объекты, на которые остались ссылки после их удаления (dangling pointers), некорректное использование weak / unowned, ошибки в коде на C / Objective-C. Включите Zombie Objects в схеме запуска Xcode. Этот режим превращает освобожденные объекты в «зомби» и логирует попытки доступа к ним, четко указывая на проблемный объект. Также используйте Address Sanitizer для выявления более тонких ошибок работы с памятью.


🔵Сигнал 2: SIGSEGV:

Попытка чтения или записи в область памяти, доступ к которой запрещен. Низкоуровневая и опасная ошибка. Причиной может быть работа с Unsafe указателями в Swift, ошибки в нативном коде (C / C++ / Obj-C), порча памяти (memory corruption). Тщательно рецензируйте весь код, использующий UnsafeRawPointer и аналоги. Запустите приложение с Address Sanitizer. Установите символьные точки останова на функции работы с памятью.


🔵Сигнал 3: EXC_CRASH / SIGABRT:

Приложение само вызвало аварийное завершение. Это самый прозрачный тип краша. Причиной может быть срабатывание fatalError(), принудительное извлечение опционала (!), неудачное выполнение assert() или precondition, ошибки валидации в Core Data. Внимательно читайте сообщение в консоли, оно часто напрямую указывает на причину. Изучите верхушку стек-трейса, чтобы найти строку вашего кода, которая инициировала остановку. Замените force unwrap на безопасные конструкции (if let, guard let).


🔵Сигнал 4: SIGTRAP / SIGILL:

Выполнение недопустимой инструкции процессора или срабатывание контрольной точки (trap). Причиной может быть срабатывание assertionFailure в релизной сборке, дебаг-проверки, которые сработали не в той среде, ошибки в условиях precondition. Проверьте, не активны ли строгие проверки (assert) в релизной сборке. Сравните поведение Debug и Release версий. Убедитесь, что все предположения о данных, защищенные precondition, корректны.


🔵Сигнал 5: Out of Memory, OOM:

Приложение превысило лимит памяти, выделенный системой и было завершено. Причиной может быть кэширование больших изображений без ограничений, утечки памяти (retain cycles), удержание в памяти огромных массивов данных. Запустите Memory Graph Debugger (кнопка с тремя кругами в Xcode) для визуализации графа объектов и поиска циклов сильных ссылок. Используйте Allocations Instrument для отслеживания роста потребления памяти во времени. Внедряйте инструменты для снижения давления памяти (например, NSCache вместо словаря для изображений).


🔵Сигнал 6: Watchdog Termination, код 0x8BADF00D:

Система усыпила приложение за блокировку главного потока более чем на несколько секунд. Причиной могут быть синхронные сетевые запросы на главном потоке, декодирование большого JSON, тяжелые вычисления в SwiftUI.body. Используйте инструментарий Time Profiler для записи и анализа активности потоков. Найдите операции, блокирующие main thread. Выносите длительные задачи с Main Actor с помощью Task.detached или фоновых очередей.


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22105🔥2🙏1
🔢 @Observable в SwiftUI: почему это больше, чем замена ObservableObject.

SwiftUI продолжает эволюционировать, и одним из самых значимых изменений за последнее время стало появление макроса @Observable. Многие разработчики до сих пор используют привычный ObservableObject, не до конца понимая, что новый подход - это не просто синтаксический сахар, а фундаментальное улучшение в философии управления состоянием. Если вы все еще заставляете свои модели подчиняться протоколу ObservableObject и разбрасываете @Published, самое время разобраться, как @Observable делает код не только чище, но и эффективнее на системном уровне.


Философский сдвиг - от ручного объявления к автоматическому обнаружению изменений:

Ключевое различие между двумя подходами лежит в парадигме. ObservableObject требует от вас явного объявления намерений. Вы помечаете класс протоколом, а каждое свойство, которое должно публиковать изменения - модификатором @Published. Это императивный подход: «Я, разработчик, говорю системе, за чем именно нужно следить».

@Observable реализует противоположную, декларативную философию. Вы просто помечаете класс макросом @Observable. Система на этапе компиляции анализирует ваш код и автоматически определяет, какие свойства могут изменяться и требуют наблюдения. Вы декларируете: «Это класс с наблюдаемым состоянием», а система сама решает, как за этим эффективно следить.


Технические отличия - Runtime vs Compile-time наблюдение:

Этот философский сдвиг имеет прямые технические последствия для производительности и поведения.

🔵ObservableObject (Runtime Observation): работает через механизм Combine и объект ObservableObjectPublisher. Когда изменяется свойство с @Published, оно через objectWillChange.send() асинхронно уведомляет всех подписчиков (ваши View) о том, что что-то в этом объекте поменялось. View затем вынуждены пересчитать свое тело, чтобы понять, изменились ли конкретные данные, которые они отображают. Это приводит к потенциально избыточным перерисовкам.

🔵@Observable (Compile-time Observation): макрос раскрывается в код, который реализует гранулярное отслеживание доступа. SwiftUI на этапе компиляции строит точные связи между конкретными свойствами модели и конкретными View, которые их используют. Когда свойство изменяется, система точно знает, какие именно View зависят от этого конкретного свойства и обновляет только их. Это устраняет лишние перерисовки и повышает производительность.


🔗 Ссылка на документацию Apple


💡 Вывод:

Появление @Observable - это не просто замена одного модификатора другим. Это шаг SwiftUI к более зрелой, эффективной и декларативной модели реактивности. Он переносит нагрузку с разработчика (которому больше не нужно вручную расставлять флажки для системы) на компилятор, который может оптимизировать наблюдение за состоянием с недоступной ранее точностью.

ObservableObject выполнил свою историческую роль, заложив основы реактивного программирования в SwiftUI. @Observable - это его логическое и технологическое развитие, предлагающее тот же результат с меньшими усилиями и большей эффективностью.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
19👍145🔥3👀1
Друзья!

Хочу вас познакомить с замечательным пабликом SwiftyGroup! Здесь вы найдете ответы на самые актуальные вопросы с собеседований, а также сможете порешать интересные задачи и ознакомиться с полезными статьями.

В SwiftyGroup мы еженедельно публикуем:

Вопросы и ответы с реальных собеседований
Статьи по подготовке к собеседованиям и развитию профессиональных навыков
Задачи для самостоятельного решения и проверки своих знаний
Присоединяйтесь к нашему сообществу и будьте всегда готовы к любым профессиональным вызовам!
10🗿4🔥3🤔1
🔢 Как добавить текстовый ввод прямо в push-уведомления iOS.

Всем привет! Сегодня разберем одну из мощных, но часто упускаемых из виду возможностей iOS - текстовый ввод прямо из уведомления. Представьте: пользователь получает сообщение и может сразу ответить, не открывая приложение. Это не магия, а встроенный механизм платформы, который открывает новые сценарии взаимодействия.

Большинство приложений используют уведомления как односторонний канал: показали сообщение -> нажали -> перешли в приложение. Но iOS уже несколько лет позволяет превращать пуши в интерактивные интерфейсы. Помимо стандартных кнопок, система поддерживает поле для ввода текста - идеально для быстрых ответов, подтверждений или простых команд.


Философия категорий:


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


// Определяем действие с текстовым полем
let quickReplyAction = UNTextInputNotificationAction(
identifier: "QUICK_REPLY",
noscript: "Ответить",
options: [],
textInputButtonTitle: "Отправить",
textInputPlaceholder: "Ваш ответ"
)

// Создаем категорию для сообщений чата
let chatCategory = UNNotificationCategory(
identifier: "CHAT_MESSAGE",
actions: [quickReplyAction],
intentIdentifiers: [],
options: []
)

// Регистрируем категорию в системе
UNUserNotificationCenter.current().setNotificationCategories([chatCategory])



Как сообщить системе, какое уведомление показать:

Категория - это шаблон. Чтобы она сработала, нужно указать ее идентификатор при создании самого уведомления:


let content = UNMutableNotificationContent()
content.noscript = "Новое сообщение"
content.body = "Привет! Как дела?"
content.categoryIdentifier = "CHAT_MESSAGE" // Ключевая связка


Теперь, когда это уведомление появится, система автоматически добавит к нему кнопку «Ответить» с текстовым полем.


Обработка введенного текста:


func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
if response.actionIdentifier == "QUICK_REPLY", let textResponse = response as? UNTextInputNotificationResponse {
let userText = textResponse.userText
// Отправляем текст на сервер, сохраняем локально и т.д.
processQuickReply(userText)
}

completionHandler()
}



Ограничения и особенности:

🔵Нельзя кастомизировать UI: поле ввода и кнопка - системные, их внешний вид определяется iOS.

🔵Требуется разрешение на уведомления: без requestAuthorization функция не работает.

🔵Работает только с категориями: простые уведомления без categoryIdentifier не поддерживают текстовый ввод.

🔵Лимит на количество действий: вместе с текстовым можно добавить еще до 3 обычных действий.

🔵Фокус на кратковременные сценарии: система не предназначена для длинных текстов - это инструмент для быстрых реакций.


🔗 Ссылка на подробную статью


💡 Вывод:

Добавление текстового ввода в уведомления - это шаг к тому, чтобы сделать пуши не просто напоминаниями, а полноценными точками взаимодействия. Это меняет парадигму: вместо «уведомить и ждать открытия приложения» мы получаем «уведомить и сразу получить ответ».

UNTextInputNotificationAction - это не просто техническая деталь, а инструмент для сокращения пути пользователя к цели. В мире, где внимание - самый ценный ресурс, возможность быстро выполнить действие в один тап может стать реальным конкурентным преимуществом.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20👍1052🙏1🤝1
🔢 Как Group в SwiftUI обманывает ваши ожидания и делает код непредсказуемым.

Сегодня разберем одну из самых коварных конструкций в SwiftUI, которая выглядит безобидно, но может стать источником трудноуловимых багов. Речь о модификаторе Group. Многие используют его для группировки представлений, не понимая, что на самом деле происходит под капотом. Group - это не layout-контейнер вроде VStack или HStack, а особый механизм, который меняет правила применения модификаторов к дочерним представлениям.

Основная проблема в том, что Group ведет себя непрозрачно. Вы применяете модификатор к группе, думая, что он применяется один раз, а на самом деле SwiftUI может применить его к каждому дочернему элементу отдельно. Это особенно опасно с модификаторами жизненного цикла, такими как onAppear и task.


Сценарий-ловушка - двойной вызов логики:


struct ContentView: View {
@State private var isLoading = true

var body: some View {
Group {
if isLoading {
ProgressView()
} else {
DataView()
}
}
.onAppear {
loadData() // Опасно! Может вызваться несколько раз
}
}

private func loadData() {
// Загрузка данных
isLoading = false
}
}


Интуиция подсказывает: onAppear сработает один раз, когда появится Group. Реальность SwiftUI может быть другой. В зависимости от версии iOS и контекста (особенно внутри List), модификатор onAppear может быть применен к каждому дочернему представлению, что может привести к дублирующим сетевым запросам или нарушению бизнес-логики.


Почему это происходит:

Group в SwiftUI - это не самостоятельное представление с собственной областью видимости модификаторов. Это скорее помощник, который передает модификаторы своим детям. Когда вы пишете .onAppear для Group, система может интерпретировать это как «применить onAppear ко всем элементам внутри».


Что лучше использовать вместо Group:


🔹 Явные layout-контейнеры:

Если нужно расположить элементы - используйте предназначенные для этого инструменты:


// Вместо Group для вертикального расположения
VStack {
Text("Заголовок")
Text("Описание")
}

// Вместо Group для горизонтального
HStack {
IconView()
TextView()
}

// Для наложения
ZStack {
BackgroundView()
ContentView()
}


Эти контейнеры дают четкую визуальную и логическую структуру. Они не маскируют, а декларируют отношения между элементами.


🔹 Вынос в отдельные View:

Если Group добавляется для логической группировки - это верный признак, что пора создать отдельное представление:


// Вместо
Group {
UserAvatarView()
UserNameView()
UserStatusView()
}
.padding()

// Создаем
struct UserHeaderView: View {
var body: some View {
VStack {
UserAvatarView()
UserNameView()
UserStatusView()
}
.padding()
}
}


Преимущества:

🔵Читаемость кода улучшается.

🔵Возможность повторного использования.

🔵Изоляция модификаторов и логики.

🔵Упрощение тестирования.


🔹 ViewBuilder для сложных условий:

Для сложных условных конструкций можно использовать @ViewBuilder:


@ViewBuilder
var conditionalContent: some View {
if conditionA {
ViewA()
} else if conditionB {
ViewB()
} else {
DefaultView()
}
}

var body: some View {
VStack {
conditionalContent
}
.onAppear {
// Безопасно: применяется к VStack, а не к каждому условию
}
}



🔗 Ссылка на подробную статью


💡 Вывод:

SwiftUI - это декларативный фреймворк, где явность и предсказуемость должны быть приоритетом. Group нарушает этот принцип, создавая неочевидные связи и поведение.

Отказ от Group в пользу явных решений делает код не только безопаснее, но и понятнее. Вы перестаете полагаться на скрытое поведение фреймворка и начинаете явно декларировать свои намерения. В мире SwiftUI, где компилятор и рантайм делают много магии, такая явность - это не прихоть, а необходимость для создания стабильных и поддерживаемых приложений.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🤯125🔥21🤝1
🔢 Невидимый тормоз: как Codable съедает производительность вашего приложения.

Если вы пишете на Swift, вы почти наверняка используете Codable. Это элегантное решение для сериализации, ставшее стандартом де-факто. Но за кажущейся простотой скрывается сложный механизм, производительность которого в реальных сценариях часто далека от идеала.

Сегодня обсудим главные тезисы из статьи, в которой рассказывается как Codable ведет себя в условиях большого приложения с сотнями моделей и тысячью строк JSON на старте. Ребята обнаружили, что JSONDecoder и JSONEncoder могут тратить сотни миллисекунд на, казалось бы, простые операции, и нашли способы ускорить их работу в разы. Результатом этой работы стал Pull Request в репозиторий swift-foundation.


Где искать настоящие проблемы, а не синтетические цифры:

Первая ошибка - измерять производительность Codable в вакууме, декодируя один и тот же объект миллион раз в цикле. В реальности приложение при старте часто парсит множество разных моделей данных, и каждая из них встречается впервые. Именно в этот момент проявляются издержки динамической природы Swift Runtime.

Ключевой метод, который становится узким местом - swift_conformsToProtocolMaybeInstantiateSuperclasses. Он ищет, соответствует ли тип требуемому протоколу. В приложении с обширной кодовой базой таких соответствий может быть сотни или тысячи. Линейный поиск по этому массиву при каждом первом обращении к новому Codable-типу - дорогая операция.


Первый пример из кода Foundation:

// Пример из старой реализации JSONDecoder
func unwrap<T: Decodable>(...) throws -> T {
...

if T.self is _JSONStringDictionaryDecodableMarker.Type {
return try self.unwrapDictionary(...)
}
}


Оператор is здесь запускает поиск соответствия типа T протоколу _JSONStringDictionaryDecodableMarker. Это происходит даже когда в этом нет необходимости (например при стандартной стратегии преобразования ключей).

Что изменили: Добавили проверку флага keyDecodingStrategy.isDefault. Каст к специальному протоколу теперь выполняется только тогда, когда это действительно нужно. Аналогичную оптимизацию применили и для JSONEncoder.


Скрытая цена CodingKey:

Каждый автоматически сгенерированный enum CodingKeys - это не просто перечисление. Это полноценный тип, который реализует протоколы CodingKey, Hashable, Equatable, CustomStringConvertible, CustomDebugStringConvertible. Каждое такое соответствие добавляет запись в тот самый массив, по которому работает медленный поиск.


Проблема усугубляется в generic-контейнерах:

// Объявление из стандартной библиотеки
public struct KeyedDecodingContainer<K: CodingKey>


При создании такого контейнера (а он создается для каждой модели в container(keyedBy:)) Runtime снова ищет соответствие вашего конкретного CodingKeys.self протоколу CodingKey. При 6000 уникальных моделей в приложении это 6000 лишних поисков при первом запуске.

Новый подход: Максимальный отказ от уникальных CodingKeys в пользу общего типа, например, String или специальной структуры AnyCodingKey. Это дает двойной выигрыш:

🔵Резко сокращает количество вызовов тяжелого метода.

🔵Уменьшает размер бинарного файла приложения (каждый CodingKeys добавляет ~1.8 КБ кода).


💡 Вывод:

Работа с Codable напоминает движение по скоростному шоссе: на пустой дороге кажется, что все идеально, но в час пик начинаются пробки. Исследование показало, что производительность сериализации в Swift - это не вопрос синтетических тестов, а практическая проблема, влияющая на реальные метрики приложений. Узкие места скрыты не в алгоритмах парсинга JSON, а в фундаментальных механизмах языка: динамических проверках времени выполнения и создании избыточных типов.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1912🤯5🔥2🤔1👀1
Forwarded from Кот Денисова
👨‍💻 Искусство разговора с ИИ: как заставить нейросети писать качественный код.

Современные инструменты искусственного интеллекта становятся неотъемлемой частью рабочего процесса разработчиков. Однако их реальная полезность напрямую зависит от качества формулируемых запросов. Грамотный промпт-инжиниринг превращает ИИ из простого генератора кода в полноценного партнера по разработке.


Значение контекста:

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


Специфичность формулировок:

Размытые вопросы порождают общие ответы. Вместо краткого «почини баг» эффективнее описывать конкретные симптомы: «функция возвращает null вместо ожидаемого объекта». Четкое описание ожидаемого и фактического поведения позволяет ИИ точнее диагностировать проблему.


Стратегия декомпозиции:

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


Метод ролевого моделирования:

Назначение ИИ конкретной профессиональной роли значительно влияет на стиль и глубину ответа. Запросы в формате «действуй как senior-разработчик» или «проанализируй код как эксперт по безопасности» активируют соответствующие паттерны в модели, что приводит к более экспертному результату.


Метод последовательных улучшений:

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


🔗 Ссылка на подробную статью


💡 Вывод:

Ключевой принцип эффективного взаимодействия: качество ответа ИИ прямо пропорционально качеству входного запроса. Инвестирование времени в составление продуманного промпта многократно окупается за счет снижения затрат на последующие исправления и доработки.


➡️ Кот Денисова
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥7👀321
🔢 Революция в подходах к безопасной многопоточности в Swift 6.

С выходом Swift 6 разработчики получили строгие гарантии защиты от состояний гонки (data-race safety) в многопоточном коде. Однако эти гарантии принесли и новые сложности - система стала предъявлять требования даже к тому коду, который выполняется последовательно. В новом видении команда Swift Evolution предлагает сделать модель безопасности более гибкой и дружелюбной, особенно для однопоточных приложений и плавной миграции.


Суть проблемы - безопасность там, где угрозы нет:

Текущая модель Swift 6 по умолчанию предполагает, что любой код может выполняться в нескольких потоках одновременно. Это приводит к избыточным требованиям в сценариях, где реальной многопоточности нет.

// Пример ложного срабатывания
class AppSettings {
static let current = AppSettings() // Ошибка: небезопасно для параллельного доступа
}


Хотя если всё приложение работает в основном потоке, состояние гонки здесь невозможно.


Новый подход - контекстные умолчания:

Основная идея - позволить системе различать контекст выполнения. Для модулей приложений и скриптов предлагается устанавливать изоляцию к @MainActor по умолчанию, отражая их фактическое однопоточное поведение.

// Будущее: умолчание для модуля приложения
// module.moduleconfig: default-isolation = main-actor

class DataCache {
static let shared = DataCache() // Теперь корректно
var items: [String] = []
}

class ViewModel { // Неявно @MainActor
func load() {
DataCache.shared.items.append("data") // Работает без аннотаций
}
}



Изолированные реализации протоколов:

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

protocol Serializable {
func serialize() -> Data
}

@MainActor
class UserProfile: Serializable {
private var data: [String: Any] = [:]

// Изолированная реализация протокола
func serialize() -> Data {
return try! JSONSerialization.data(withJSONObject: data)
}
}



Переосмысление async-поведения:

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


Что это значит для разработчиков:

🔵Меньше рутинных аннотаций @MainActor в UI-коде.

🔵Упрощение миграции legacy-проектов.

🔵Более понятные ошибки компиляции.

🔵Сохранение строгой безопасности там, где она действительно нужна.


🔗 Ссылка на подробную статью


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
15👍11🔥5🤝21👏1
👨‍💻 Swift-интервью: как одна архитектурная ошибка стоила кандидату работы.

Привет, друзья! Сегодня разберем реальный кейс технического собеседования на позицию Swift-разработчика из данной статьи. История интересна не столько кодом, сколько глубинным пониманием системного дизайна, которое часто отделяет просто разработчика от того, кто способен проектировать библиотеки уровня Apple.


Задача, которая оказалась ловушкой:

Кандидату в команду SwiftUI для macOS дали задачу: реализовать метод adjacentPairs(), возвращающий последовательные пары элементов. Базовую функциональность он реализовал успешно, создав ленивую последовательность. Однако интервьюер задал каверзный вопрос о производительности цепочки .adjacentPairs().reversed().prefix(2). Именно здесь и проявился недостаток глубины решения.


Слепое следование паттерну вместо анализа:

Кандидат взял за образец реализацию uniqued() из Swift Algorithms. Это логично, но критично - он не проанализировал, подходит ли этот шаблон для его задачи. uniqued() должен хранить историю уникальных элементов в Set, что делает обратную итерацию очень затратной. Его же алгоритм adjacentPairs() работал только с соседними индексами и не требовал накопления состояния.


Последствие - неоптимальная производительность:

Из-за поддержки только протокола Sequence операция .reversed() не могла работать лениво, ей приходилось сначала пройти всю последовательность до конца. Если бы кандидат добавил поддержку протокола BidirectionalCollection для соответствующих базовых типов, reversed() остался бы ленивой операцией.


// Ключевое улучшение - условная поддержка протоколов
extension AdjacentPairsSequence: BidirectionalCollection
where Base: BidirectionalCollection {
// Эффективная обратная итерация без материализации
}



Что на самом деле проверяли:

Интервью оценивал способность проектировать API, а не просто писать код:

🔵Понимание модели данных: осознает ли кандидат, какие возможности дают разные протоколы коллекций?

🔵Мыслит ли системно: как его решение поведет себя в комбинации с другими стандартными операциями?

🔵Способность к оптимизации: может ли он увидеть потенциал для улучшения архитектуры?


💡 Вывод:

История с этим собеседованием прекрасно иллюстрирует разницу между подходом прикладного и системного разработчика. Прикладной разработчик спрашивает: «Работает ли мой код?» Системный: «Оптимален ли мой дизайн API в контексте всей экосистемы?»

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

Этот случай - важное напоминание: при проектировании любых абстракций, особенно в языке типа Swift, критически важно оценивать не только их непосредственную функцию, но и то, какие возможности они открывают (или закрывают) для будущих комбинаций и оптимизаций. Умение видеть эту картину целиком и отличает разработчика, который пишет код, от того, кто создает инструменты.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1573🤯2🙏1👀1
👨‍💻 Финансовый рычаг: как Apple будет взыскивать неоплаченную комиссию.

Лицензионное соглашение Apple для разработчиков - документ, который большинство просматривает по диагонали, ставя галочку в конце. Но в декабре 2025 года в нем появились изменения, которые могут напрямую повлиять на финансовые потоки тысяч разработчиков по всему миру. Речь идет не о новых API или технических требованиях, а о перераспределении финансовых полномочий между платформой и теми, кто создает для нее приложения. Эти правки - тихая революция в отношениях платформа-разработчик, происходящая в мелком шрифте юридического документа.


Юридический механизм, который меняет баланс сил:

В разделах 3.4 Приложений 2 и 3 появилась формулировка, дающая Apple право «зачитывать или возмещать суммы, причитающиеся Apple». На обычном языке это означает: если Apple считает, что вы должны ей денег за комиссии, сборы или налоги - она может просто взять эти деньги с вашего счета разработчика без отдельного уведомления или согласования.


Цепная реакция ответственности:

Еще более значимое изменение: расширение ответственности на аффилированных лиц, материнских или дочерних компаний. На практике это создает прецедент групповой ответственности.

Представьте сценарий: небольшая студия разрабатывает нишевое приложение, которое использует альтернативные платежи. У студии есть материнская компания, которая выпускает другое, более популярное приложение через App Store. Если студия задолжает Apple по комиссиям, Apple получает право взыскать эти деньги с доходов материнской компании от другого приложения.

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


Зачем это Apple сейчас?

Эти изменения нельзя рассматривать изолированно. Они происходят на фоне:

🔵Регуляторного давления в ЕС: DMA вынудила Apple допустить альтернативные платежные системы, но компания ищет способы сохранить контроль над денежными потоками.

🔵Судебных баталий в США: решение о возможности взимания комиссий (хоть и не полных 27%) создало прецедент, который нужно юридически закрепить.

🔵Экспансии в Японию: новые правила для японского рынка требуют унификации механизмов взимания платежей.

🔵Перехода от CTF к CTC в январе 2026: более сложная процентная модель комиссий требует более гибких инструментов взыскания.

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


Побочные изменения - не только про деньги:

В том же обновлении есть и другие значимые правки:

🔵Запрет на скрытую запись: формулировка «без ведома пользователей» может осложнить жизнь инструментам аналитики и отладки, которые используют запись сессий.

🔵Требования к голосовым помощникам: активация через боковую кнопку iPhone теперь регулируется отдельно, что указывает на стратегический интерес Apple к голосовым интерфейсам.

🔵API для возраста и контента: усиление контроля над возрастными рейтингами и тематикой приложений.

Эти изменения рисуют картину платформы, которая усиливает контроль сразу по нескольким фронтам: финансовому, этическому, технологическому.


💡 Вывод:

Обновленное лицензионное соглашение - это не просто техническая правка, а отражение фундаментального сдвига в философии Apple как платформы. Компания переходит от модели «мы предоставляем услуги, вы платите комиссию» к модели «мы партнеры, но мы определяем правила расчетов».

Для разработчиков это означает новую реальность: финансовая прозрачность становится двусторонней улицей. Если раньше вы отчитывались перед Apple о своих доходах, то теперь Apple получает право самостоятельно определять, сколько вы должны, и взыскивать эту сумму наиболее удобным для себя способом.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👀15👍7🤯31🤔1🗿1
🔨 Один пакет для всех тестов: радикальный подход к ускорению CI.

Представьте CI-пайплайн, где каждый пул-реквест собирается 30 минут. Разработчики теряют фокус, контекст переключается, а поток работы прерывается. Теперь представьте тот же пайплайн, но работающий за 2.5 минуты. Это не фантастика, а реальная история оптимизации, которая началась с трех Mac mini и закончилась архитектурным прорывом в организации сборок Xcode.


Когда рост становится проблемой:

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

Казалось логичным: изменили код в пакете А - запустились только его тесты. Но реальность оказалась сложнее. Основное приложение собиралось 12 минут - это был физический предел скорости. Остальное время уходило на дублирование работы: двадцать разных процессов могли одновременно пересобирать одни и те же зависимости, потому что каждый начинал с нуля.


Миф о портативном кэше:

Первая мысль любого инженера при оптимизации сборок - кэширование. С Xcode эта идея разбивается о суровую реальность.

Оказывается, DerivedData - директория, где Xcode хранит промежуточные артефакты сборки - содержит абсолютные пути, вшитые прямо в файлы. Попробуйте скопировать эту папку в другое место и Xcode просто проигнорирует ее, как будто кэша не существует.

Попытка использовать стандартный механизм кэширования GitHub тоже провалилась: 20 гигабайт данных нужно было скачивать перед каждой сборкой. На обычном интернет-соединении это занимало больше времени, чем полная пересборка проекта.

Но самая глубокая проблема обнаружилась дальше: Xcode принципиально не делится артефактами между разными типами целей. Приложение и Swift Package, даже если они используют один и тот же код, компилируются независимо. Два разных пакета в одном рабочем процессе тоже не могут использовать общие промежуточные файлы. Получался абсурд: изменение в одной библиотеке запускало двадцать параллельных процессов, каждый из которых компилировал одни и те же исходники с нуля.


Архитектурное решение - два мира, два кэша:

Прорыв пришел с парадоксальной идеей: а что если на время CI временно объединить все 89 Swift-пакетов в один гигантский пакет?

Такой подход дает лучшее из двух миров: максимальное повторное использование скомпилированного кода для тестирования и строгий контроль зависимостей для продакшен-сборки.


Система слотов - стабильность через постоянство:

Ключевое открытие оказалось удивительно простым: единственный способ заставить Xcode надежно использовать кэш - никогда не перемещать его. Директория DerivedData должна оставаться на одном и том же месте всегда.

Так родилась концепция «слотов» - фиксированных рабочих каталогов, которые процессы CI не копируют, а используют напрямую.


Интеллектуальный отбор тестов:

Объединение 91 конфигурации в единую систему потребовало умного алгоритма определения того, что действительно нужно проверить. На практике это выглядит так: изменили одну строку в библиотеке - автоматически запустились 12 связанных тестовых наборов и 3 сборки приложений. 61 несвязанный тест был пропущен. В сочетании с предварительно подготовленными кэшами большинство проверок затрагивают менее 20% кодовой базы.


💡 Вывод:

Настоящая ценность этой оптимизации измеряется не в минутах, а в восстановленном потоке работы. Когда обратная связь от системы непрерывной интеграции приходит за 2,5 минуты вместо 30, исчезает внутреннее сопротивление перед созданием пул-реквестов. Разработчики остаются погруженными в задачу, ошибки обнаруживаются и исправляются сразу, циклы итерации становятся короче и эффективнее.

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
16👍10🔥4🤔21👀1
Forwarded from Кот Денисова
Мой подход к изучению нового языка или технологии всегда один: я начинаю практиковаться на личном проекте.

В этот раз, освоение Rust тоже началось с разработки серверной части для нового приложения. Работает бэкенд на Rust быстро и стабильно, но, если честно, процесс разработки занимает примерно в три раза больше времени по сравнению с привычным для меня PHP.

Само приложение будет простым, пишу его на Swift под iOS и macOS. Как только Swift Android SDK будет работать стабильно, адаптирую его под Android.

Подробности будут позже.


➡️ Кот Денисова
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1810🔥3👏1🤝1
👨‍💻 iOS 26.3: теперь реклама приложений в App Store будет почти неотличимой.

Компания Apple тестирует новый дизайн рекламных блоков в поиске App Store. Раньше платные позиции выделялись синим фоном - четкий сигнал, что это реклама. Теперь фон убран, и карточка выглядит точно так же, как результаты поиска. Единственное отличие - небольшая метка «Ad», которая почти незаметна.

Изменение тестируется в iOS 26.3 как A/B-тест: одним пользователям показывают старый дизайн, другим новый. Это стандартная практика для оценки влияния на метрики вовлеченности. Вероятно, Apple хочет проверить, насколько можно повысить кликабельность рекламы, не вызывая явного недовольства пользователей.

С технической стороны, это изменение упрощает интеграцию нескольких рекламных блоков в одну выдачу - Apple недавно объявила о расширении рекламного инвентаря. Когда все результаты выглядят одинаково, страница не кажется перегруженной рекламой.

Есть и этический вопрос. Регуляторы требуют четкого обозначения рекламы, но маленькая метка на белом фоне - это формальное соблюдение правил, а не реальная помощь пользователю. В условиях быстрого скроллинга такой маркер легко пропустить.

Для разработчиков это значит возможный рост стоимости рекламы, если кликабельность увеличится, возрастут и ставки в аукционе. Также придется уделять больше внимания иконкам и скриншотам, поскольку визуальное отличие от органических результатов исчезло.


🔗 Ссылка на подробную статью


💡 Вывод:

Apple балансирует между монетизацией и пользовательским опытом. Новый дизайн рекламы - явный шаг в сторону повышения доходов, даже если это происходит за счет прозрачности. Пользователям станет сложнее отличать платное размещение от настоящих рекомендаций системы.

В долгосрочной перспективе такие изменения могут подорвать доверие к платформе. Если сегодня рекламу сложно отличить от контента в App Store, завтра пользователи начнут сомневаться и в других разделах экосистемы.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯17👀11🔥4👏1🙏1
🔢 Swift Concurrency: какие настройки компилятора действительно важны.

С переходом на Swift 6 и активным использованием async/await многие разработчики сталкиваются с непонятными ошибками компиляции и неочевидным поведением приложения. Часто проблема кроется не в коде, а в настройках компилятора. Разберем, какие параметры действительно влияют на корректную работу Swift Concurrency и как их правильно настроить.

Настройки компилятора Swift для конкурентности можно разделить на три категории: фундаментальные, рекомендательные и экспериментальные. Понимание различий между ними сэкономит часы отладки.


Фундаментальные настройки (нельзя игнорировать):

Эти параметры определяют базовое поведение системы типов в конкурентной среде. Их неправильная конфигурация ведет к неопределённому поведению или падениям.

🔹 StrictConcurrency - главный переключатель строгости проверок:

🔵minimal: практически отсутствуют проверки (опасно для прода).

🔵targeted: проверки только для кода с аннотациями @Sendable, @MainActor.

🔵complete: полная проверка всего кода (рекомендуется для новых проектов).

🔹 GlobalConcurrency - распространяет правила изоляции на глобальные переменные и синглтоны. Без этой настройки статические данные становятся потенциальными источниками гонок данных.

🔹 DynamicActorIsolation - превращает потенциальные data races в предсказуемые runtime-ошибки. Включайте, только если готовы к дополнительным проверкам во время выполнения.


Рекомендательные настройки (улучшают опыт разработки):

Эти параметры не критичны для корректности, но значительно упрощают работу с конкурентным кодом.

🔹 NonisolatedNonsendingByDefault: меняет семантику nonisolated функций. Рекомендуется включать в новых проектах, так как делает поведение более интуитивным и предотвращает распространенные ошибки новичков.

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

🔹 RegionBasedIsolation: экспериментальная, но многообещающая функция, которая вводит региональную изоляцию данных. Позволяет точечнее контролировать доступ к изменяемым состояниям.


Настройки, которые можно отложить:

Некоторые параметры решают узкоспециальные задачи или находятся в активной разработке:

🔹 ExistentialAny, MemberImportVisibility, InternalImportsByDefault - связаны с будущими изменениями системы типов и модульности. Не влияют на конкурентность напрямую.

🔹 BareSlashRegexLiterals, ForwardTrailingClosures - синтаксический сахар, не затрагивающий семантику async/await.


Рекомендации по настройке:

Для нового проекта на Swift 6:


// В настройках Xcode или Package.swift
SWIFT_STRICT_CONCURRENCY = "complete"
ENABLE_GLOBAL_CONCURRENCY = YES
ENABLE_NONISOLATED_NONSENDING_BY_DEFAULT = YES


Для миграции существующего проекта:

🔹 Начните с StrictConcurrency = "targeted"

🔹 Постепенно добавляйте аннотации @MainActor и @Sendable

🔹 Включите GlobalConcurrency после аудита глобальных состояний

🔹 Перейдите на complete режим после покрытия основных модулей


Важное замечание про зависимости:

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


🔗 Ссылка на подробную статью


💡 Вывод:

Правильная настройка компилятора - не роскошь, а необходимость для стабильной работы Swift Concurrency. Начинайте с консервативных параметров при миграции legacy-кода и смело используйте строгие проверки в новых проектах. Помните, что StrictConcurrency = "complete" - это не просто дополнительная проверка, а гарантия того, что компилятор поможет найти скрытые проблемы с параллельным доступом до того, как они проявятся у пользователей.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍178🔥3🙏21👏1
Forwarded from Кот Денисова
👨‍💻 Кроссплатформа, BDUI или натив: как сделать верный выбор.

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

Бизнес-логика здесь проста и неизменна: компания ищет не «самую правильную» технологию, а самую выгодную. В условиях, когда для многих компаний приоритетом стало банальное выживание, разговоры о технологическом эстетизме отходят на второй план. Именно этим и обусловлен перманентный интерес к альтернативам нативной разработки: PWA, кроссплатформе и BDUI. Отрицать их привлекательность наивно, так как они сулят сокращение издержек и ускорение выхода на рынок.


Почему кроссплатформа не панацея:


Несмотря на заманчивые обещания, у кроссплатформенных решений есть системные минусы, с которыми столкнулись многие проекты:

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

🔹Компромиссы в производительности и UX: создание сложных анимаций, работа с графикой или реализация «тяжелых» фич вроде плавного чата с высокой частотой кадров (как в Telegram) упирается в ограничения мостового слоя. Результат: либо 30 FPS вместо стабильных 60, либо бесконечные костыли, усложняющие поддержку.


BDUI: хитрый компромисс:


Концепция Backend-Driven UI (BDUI) сегодня - это, пожалуй, самый сильный конкурент «чистой» кроссплатформы. Ее суть в том, что сервер присылает на устройство конфигурацию интерфейса, а нативное приложение его отрисовывает готовыми, «родными» компонентами.

🔹Преимущество: это позволяет гибко менять интерфейс без публикации обновлений в магазины приложений. По скорости итераций и стоимости поддержки это часто выигрывает у кроссплатформы, сохраняя при этом нативное качество отображения.

🔹Риск: однако это игра с правилами магазинов приложений. Если с сервера приходит функциональность, кардинально меняющая поведение приложения по сравнению с тем, что было на ревью, это чревато санкциями вплоть до блокировки.


Когда все-таки нужен натив:


Ответ лежит в плоскости продукта и его амбиций. Нативная разработка - это не просто «круто и здорово», это выбор в пользу:

🔹Максимальной производительности: высокочастотные анимации, сложные жесты, работа с графикой и аудио.

🔹Беспрецедентного пользовательского опыта (UX): полное соответствие гайдлайнам платформы, доступ ко всем системным API без посредников, мгновенный отклик.

🔹Долгосрочной стабильности: прямая работа с операционной системой минимизирует риски, связанные с обновлениями сторонних фреймворков.


💡 Вывод:

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

Споры «натив против кроссплатформы» теряют смысл. Реальный вопрос звучит иначе: «Какой набор технологий и архитектурных решений оптимален для достижения бизнес-целей этого конкретного продукта в текущих рыночных условиях?». И ответ на него каждый раз разный.


➡️ Кот Денисова
Please open Telegram to view this post
VIEW IN TELEGRAM
16👍8🙏3🔥2🫡1
This media is not supported in your browser
VIEW IN TELEGRAM
🔨 Какое влияние ваше приложение оказывает на заряд аккумулятора?

В 2025 году, в рамках WWDC компания Apple представила обновленный инструмент для анализа энергопотребления вашего приложения - Power Profiler.

Теперь в iOS, прямо из центра управления, можно запустить проверку приложения, чтобы оценить его расход заряда. Собранные данные позже анализируются в Instruments.


🔗 Читать подробнее


💡 Вывод:

Новые инструменты анализа энергопотребления - это не просто техническое обновление. Это сигнал всей индустрии: энергоэффективность стала такой же важной характеристикой приложения, как скорость работы, стабильность или дизайн.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥94👏2🙏1
🔢🏋️ Взгляд изнутри: как развивается рабочий проект Swift для Android.

Еще несколько лет назад сама идея запуска Swift на Android казалась чем-то фантастическим. Сегодня ситуация кардинально меняется. Официальная рабочая группа по адаптации языка для зеленого робота не просто делится планами, она демонстрирует конкретные инструменты и четкую дорожную карту. Давайте отбросим скепсис и разберемся, что сегодня умеет Swift на Android, какие проблемы решает и какие новые возможности открывает для разработки в принципе.


Ядро и производительность - нативный подход:

Ключевой принцип: Swift компилируется напрямую в машинный код для процессоров Android, минуя виртуальные машины. Это не обертка или трансляция, а полноценный нативный бинарник. Такой подход ставит его в один ряд по производительности с решениями на C и C++, созданными через NDK, но с критически важным отличием - встроенной безопасностью памяти и современным, выразительным синтаксисом. Для работы на устройстве вместе со сборкой поставляется собственная среда выполнения (runtime), реализующая стандартную библиотеку и фундаментальные компоненты вроде Dispatch.


Главный вызов и его решение - мост к Java-миру:

Самое сложное в адаптации Swift на Android - не компиляция, а интеграция с экосистемой. Все ключевые API платформы от работы с сенсором до уведомлений заточены под Java и Kotlin. Решение этого пазла - проект Java-совместимый и два его основных инструмента: jextract и wrap-java. Они автоматически генерируют «мостики» (биндинги), используя стандартный для нативного кода механизм JNI (Java Native Interface). Это позволяет Swift-коду вызывать Java-классы и наоборот, обеспечивая бесшовную, хотя и требующую настройки, интеграцию.


Кто уже использует на практике:

Лучшее доказательство жизнеспособности технологии - ее применение в коммерческих продуктах с миллионами установок. Вот несколько примеров:

🔵Spark (Readdle): известный почтовый клиент, использующий общую Swift-логику для iOS, Android, macOS и Windows.

🔵flowkey: приложение для обучения игре на фортепиано.

🔵Naturitas: крупный маркетплейс органических продуктов.

Эти компании доказали, что общая кодовая база на Swift для бизнес-логики - не фантастика, а рабочая стратегия, экономящая ресурсы.


Что нового? Ключевые обновления SDK:

Рабочая группа активно развивает инструментарий. Среди последних значимых улучшений:

🔵Версионирование API Android. Раньше было проблематично работать с несколькими уровнями API в одном приложении. Теперь появилась поддержка знакомых по iOS-разработке атрибутов @available и проверки #available. Это позволяет писать код, который корректно работает на разных версиях ОС, повышая гибкость разработки.

🔵Ночные сборки Swift 6.3. Запущена официальная система непрерывной интеграции (CI), которая ежедневно собирает и публикует предварительные версии SDK. Это дает смелым разработчикам доступ к самым свежим изменениям и упрощает тестирование.

🔵Фокус на инструменты разработчика. В приоритете - упрощение отладки. Ведется работа по интеграции отладчика Swift и сервера LSP (sourcekit-lsp) в популярные IDE, такие как Android Studio и Visual Studio Code, чтобы процесс написания кода стал привычным и комфортным.


🔗 Ссылка на пост в блоге


💡 Вывод:

Swift на Android перестал быть диковинкой. Это формирующийся, но уже вполне рабочий технологический стек для стратегии «общая логика - нативные интерфейсы». Он предлагает мощную альтернативу C++ для критичных к производительности задач и дает iOS-разработчикам шанс выйти на новый рынок, используя знакомый язык.

Движение вперед теперь зависит не только от рабочей группы, но и от сообщества: тестирования ночных сборок, обратной связи и создания open-source инструментов. Для Android-разработчиков это возможность заглянуть в арсенал экосистемы Apple и, возможно, найти более элегантное решение для своих сложных архитектурных задач.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
15🔥8👍41👀1