Мобильный трудоголик
1.33K subscribers
61 photos
9 videos
265 links
👨‍💻 Пишу простым языком об iOS разработке на Swift и мобильной разработке в целом.
🔹 Вошел в IT задолго до того как это стало мейнстримом.
---
‍Обо мне: https://t.me/hardworkerIT/3
Чат: @hardworkerChatIT
Канал про разработку и жизнь в ИТ: @itDenisov
Download Telegram
🔢 Swift: как defer наконец-то подружился с асинхронностью.

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

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


Что изменилось:

Теперь в async-функции вы можете писать так:


func loadData() async throws {
let resource = try await acquireResource()
defer {
await resource.release()
}
try await work(with: resource)
}



Как это работает:

Ключевая механика defer сохраняется, но теперь с поддержкой асинхронности:

🔵Гарантия выполнения: блок defer выполнится при любом выходе из функции (успех, ошибка, возврат).

🔵Ожидание завершения: если внутри defer есть await, функция дождется его завершения, прежде чем вернуть управление.

🔵Ограничение: использовать await в defer можно только внутри async-контекста.


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

Раньше для асинхронной очистки приходилось либо дублировать код на всех путях выхода, либо использовать Task { }, который не гарантировал завершения операции. Теперь очистка ресурсов (закрытие сетевых соединений, сброс состояния, отмена операций) становится такой же простой и надежной, как и в синхронном коде.


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


💡 Вывод:

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


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1913🔥42👏1🙏1👀1
This media is not supported in your browser
VIEW IN TELEGRAM
🔢 iOS 26: официальный способ прикрепить плавающие View над TabBar.

Многие годы разработчики iOS испытывали смешанные чувства при виде таких интерфейсов, как мини-плеер в приложении Apple Music или постоянная панель действий в Podcasts. С одной стороны - это удобный и интуитивный паттерн, с другой - его реализация всегда была головной болью, требующей неочевидных трюков с safeAreaInsets и ручной подгонкой размеров. С выходом iOS 26 эта эпоха подошла к концу. Apple официально представила API для создания нижних аксессуаров в UITabBarController, и это одно из тех изменений, которое кардинально упрощает жизнь.


Прощайте, костыли. Здравствуй, декларативность:

До iOS 26 интеграция любого статичного или плавающего элемента поверх таббара была упражнением в нетривиальной геометрии. Разработчики были вынуждены вручную управлять additionalSafeAreaInsets, отслеживать повороты устройства, адаптировать layout под разные состояния навигации (например, появление клавиатуры) и гарантировать, что кастомная вью не перекроет таббар и его элементы. Новый API bottomAccessory решает эту проблему радикально простым и элегантным способом. Все что требуется - это создать экземпляр UITabAccessory, передав ему ваше кастомное представление, и установить его в свойство контроллера.

let miniPlayerView = MiniPlayerView() // Кастомная вью
let accessory = UITabAccessory(contentView: miniPlayerView)
tabBarController.bottomAccessory = accessory


Система берет на себя всю ответственность за позиционирование, анимации при появлении/скрытии (через метод setBottomAccessory(_:animated:)) и корректное взаимодействие с жестами. Это переход от императивного «как это разместить» к декларативному «что я хочу показать».


Гармония с поведением таббара - новый уровень интеграции:

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


Адаптивный интерфейс через tabAccessoryEnvironment:

Одной из самых тонких проблем при создании подобных элементов была адаптация их внешнего вида к разным состояниям. Нужно ли показывать полный заголовок трека или только иконку? Как изменить layout при компактном таббаре? Для этого Apple ввела новый trait - UITabAccessory.Environment. Теперь вью может запросить у traitCollection текущее окружение (.regular, .inline, .none) и кардинально изменить свой вид или внутреннюю композицию.


contentLayoutGuide - надежный фундамент для контента:


Чтобы окончательно устранить ручные расчеты отступов, Apple добавила в UITabBarController новый UILayoutGuide - contentLayoutGuide. Привязка контента основного вью-контроллера к этому guide, автоматически гарантирует, что он всегда будет располагаться в корректной области: выше системных элементов нижней части интерфейса. Этот guide динамически обновляет свои размеры при изменениях состояния таббара, появлении клавиатуры или изменении ориентации.


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


💡 Вывод:

Введение bottomAccessory в iOS 26 - это не просто добавление еще одного свойства в API. Это значительный шаг вперед в философии UI-разработки под iOS. Apple признает популярные пользовательские паттерны и предоставляет для них первоклассные, системные инструменты, заменяя годы накопленных хаков и обходных приемов. Это снижает порог входа для создания сложных интерфейсов, повышает стабильность приложений и позволяет разработчикам сосредоточиться на логике и дизайне, а не на борьбе с фреймворком.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1710👍31🙏1👀1
🔨 Xcode - это не среда разработки, это квест на выживание.

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


Иллюзия контроля:

Современная разработка строится на предсказуемости: четких ошибках, логичном рабочем процессе, последовательной документации. Xcode систематически нарушает этот контракт. Возьмем классическую ошибку SwiftUI: «The compiler is unable to type-check this expression in reasonable time». Это не ошибка в вашем коде- это капитуляция системы. Компилятор не говорит, где проблема; он предлагает вам угадывать, разбивая выражения наугад. Это эквивалент того, как если бы строительный кран останавливался со словами «что-то тяжело», не указывая на проблемную балку.


Архитектура как наследие:

Погружение в структуру проекта - это путешествие в прошлое. Файл project.pbxproj - это не просто конфигурация, это артефакт эпохи, когда понятия «человеческий формат» считались роскошью. Merge-конфликты в этом файле - это квест, где наградой становится возможность просто открыть проект. Существование инструментов вроде xcodegen - не доказательство гибкости экосистемы, а молчаливое признание провала.


Церемония подписи кода:

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


Документация как мираж:

Попытка следовать официальным руководствам - это часто путь через зеркало. Sandbox-аккаунт для тестирования покупок должен появляться в настройках симулятора, но его нет. Вы вводите пароль снова и получаете загадочное «Password reuse not available for account». Форумы разработчиков разделены: половина утверждает, что в симуляторе это не работает, другая половина - что работает. Правда где-то посередине, но ее приходится устанавливать методом проб и ошибок, а не чтением документации.


Закрытость как система:

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


Монополия на инструменты:

Отсутствие реальных альтернатив - ключевой момент. AppCode от JetBrains был похоронен, а настройка Neovim с xcode-build-server остается увлечением для энтузиастов. CLI-инструменты плохо документированы, что делает автоматизацию и CI/CD не естественным процессом, а подвигом. Fastlane существует не для расширения возможностей, а для преодоления фундаментальных недостатков.


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


💡 Вывод:

Xcode - это не просто IDE. Это культурный код, который формирует мышление разработчика. Он учит не углубляться в суть проблем, а выполнять ритуалы: перезагрузить, очистить Derived Data, пересоздать проект. Опасность такого подхода в том, что он формирует поколение разработчиков, которые воспринимают непредсказуемость как норму. Apple создала выдающиеся продукты, но инструменты для их создания остаются парадоксом: они одновременно и мост и барьер.


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

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


Концентрация возможностей в крупных центрах.

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


Роль профессионального сообщества и нетворкинга.

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


Доступ к уникальным проектам и инновациям.

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


Влияние на формирование личного бренда.

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


💡 Вывод:

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


➡️ Кот Денисова
Please open Telegram to view this post
VIEW IN TELEGRAM
👍179👀4🗿2🔥1🤯1
🔢 Захват ссылок в Swift: когда [weak self] становится ловушкой.

Всем привет! Наткнулся на интересную статью об отладке памяти в iOS. Автор разбирает реальный кейс, где мелкий UI-баг оказался верхушкой айсберга серьезной проблемы.

С чего все началось:

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


Расследование по шагам:

Автор методично искал причину. Сначала: классические print-ы по всему стеку вызовов. Оказалось, что обработчик deep link вызывался дважды, и что важнее: от двух разных экземпляров координатора в памяти.

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


Масштаб проблемы:

Используя Memory Graph Debugger, автор обнаружил шокирующую вещь: в системе оставались жить целые копии части приложения, со всеми координаторами, сервисами и вью-моделями. Каждый перелогин добавлял новый слой в память.


Найденный виновник:

Проблема скрывалась в, казалось бы, корректном коде:


.sink(receiveValue: {
Task { [weak self] in // weak здесь не спасает!
// логика
}
})


Ошибка была в том, что [weak self] стоял во внутреннем замыкании Task, в то время как внешнее замыкание .sink захватывало self сильно по умолчанию.


Решение в одну строку:

Исправление оказалось минимальным, но критически важным:


.sink(receiveValue: { [weak self] in // weak должен быть здесь!
Task {
// логика
}
})



💡 Вывод:

Эта история наглядно показывает, как механическая, но невнимательная расстановка [weak self] может создать иллюзию безопасности, скрывая реальную утечку памяти. Мы часто действуем по шаблону, добавляя слабый захват в асинхронные блоки, забывая, что корень проблемы может находиться уровнем выше - в замыкании, которое инициирует эту асинхронную операцию. Ключевой урок здесь в том, что борьба с retain cycles требует не ритуала, а понимания полного контекста захвата, особенно при работе с цепочками и вложенными замыканиями.


➡️ Подписаться на канал
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20115🤝2👍1🙏1
🔨 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
👍166🤯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
👍19105🔥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
15👍83🔥2👀1