Иногда самые полезные изменения в языке - не громкие нововведения, а устранение небольших, но раздражающих неудобств. Те, что заставляют писать лишний код, нарушать логику или искать обходные пути. Именно таким изменением стало принятие 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 сохраняется, но теперь с поддержкой асинхронности:
Почему это важно:
Раньше для асинхронной очистки приходилось либо дублировать код на всех путях выхода, либо использовать Task { }, который не гарантировал завершения операции. Теперь очистка ресурсов (закрытие сетевых соединений, сброс состояния, отмена операций) становится такой же простой и надежной, как и в синхронном коде.
Принятие SE-0493 - это пример зрелой эволюции языка. Вместо введения сложных новых концепций, Swift устраняет конкретное, давно назревшее несоответствие между синхронными конструкциями языка и его асинхронной парадигмой. Это изменение делает асинхронный код не только безопаснее, но и чище.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19 13🔥4❤2👏1🙏1👀1
This media is not supported in your browser
VIEW IN TELEGRAM
Многие годы разработчики 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
🔥17 10👍3❤1🙏1👀1
Существует инструмент, который ежедневно определяет границы возможного для миллионов разработчиков. И часто эти границы оказываются не там, где мы ожидаем. Речь не об аппаратных ограничениях или сложности алгоритмов, а о среде, в которой рождаются приложения для экосистемы 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
👍17❤9👀4🗿2🔥1🤯1
Всем привет! Наткнулся на интересную статью об отладке памяти в 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
🔥20❤11 5🤝2👍1🙏1
Когда вы запускаете сборку проекта, под капотом запускается не один инструмент, а целый конвейер. Многие разработчики воспринимают сборку как нечто монолитное, но в современной экосистеме 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 не компилируют код сами. Они - трансляторы или фронтенды.
Ключевое преимущество - разделение ответственности и совместимость:
Польза от такого гениального решения:
Где прячется 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
В iOS-разработке есть один недооцененный инструмент, который дает доступ к метрикам, обычно скрытым от нас. Речь о MetricKit - фреймворке Apple для сбора системной диагностики с устройств пользователей. Это не просто альтернатива краш-репортам, а принципиально другой уровень понимания того, как приложение ведет себя в реальных условиях.
Стандартные инструменты показывают, что упало. MetricKit показывает, почему это произошло. Не только краши, но и зависания, энергопотребление, временя запуска и десятком других, системных параметров. Это данные, которые ОС собирает сама, без участия пользователя и с минимальным влиянием на производительность.
Особенности:
MetricKit раскрывает три слоя проблем, которые иначе остаются невидимыми:
MetricKit меняет подход к качеству приложений с реактивного на проактивный. Вместо того чтобы ждать жалоб из App Store, вы видите проблемы до того, как они станут массовыми. Это инструмент для команд, которые хотят не просто исправлять баги, а понимать фундаментальные причины проблем производительности.
Главное преимущество - объективность. Вы получаете не субъективные оценки, а точные системные метрики. Это позволяет принимать архитектурные решения на основе данных, а не предположений. Для серьезных проектов внедрение MetricKit должно быть не опцией, а стандартом разработки.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16 10🔥4❤3🤔1🙏1🤝1
Forwarded from Кот Денисова
Инфляция должностей в ИТ - это когда разработчикам дают громкие названия позиций без реального роста ответственности и зарплаты. Например:
Почему компании так делают:
В аутсорсе это была стандартная практика:
Такая практика вредит всем:
Что с этим делать:
Инфляция должностей создает системные проблемы для всей ИТ-отрасли. Когда компании массово присваивают завышенные звания без реального роста компетенций, это девальвирует ценность настоящих специалистов и затрудняет найм.
Настоящий профессиональный рост определяется не формальным званием, а тремя ключевыми факторами: углублением экспертизы, увеличением ответственности и соответствующим уровнем дохода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤6🤯3🔥1🙏1
С мая я каждый день старался радовать вас полезными постами и искренне надеюсь, что они принесли вам не только новые знания, но и реальный профессиональный рост.
Я очень благодарен за ваше внимание и активность. Сейчас я ухожу на заслуженные выходные, но в январе вернусь с новыми идеями.
Желаю вам в 2026 году:
Пусть новый год будет полон открытий и достижений!
С Новым годом!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤39👍21🙏4🔥1👏1
Всем привет! Сегодня разберем системный подход к работе с крашами iOS-приложений. Частая ошибка - пытаться сразу лезть в код, не поняв, какой именно сбой произошел. Это как лечить температуру, не зная, грипп это или воспаление легких. Каждый тип краша - это сигнал от системы, который указывает на определенный класс проблем. Когда приложение падает, операционная система отправляет сигнал (signal) о причине прекращения работы. Этот сигнал - ключ к быстрой диагностике.
Шесть основных сигналов и методы их исправления:
Приложение попыталось обратиться к участку памяти, который уже освобожден или никогда не принадлежал ему. Причиной могут быть объекты, на которые остались ссылки после их удаления (dangling pointers), некорректное использование weak / unowned, ошибки в коде на C / Objective-C. Включите Zombie Objects в схеме запуска Xcode. Этот режим превращает освобожденные объекты в «зомби» и логирует попытки доступа к ним, четко указывая на проблемный объект. Также используйте Address Sanitizer для выявления более тонких ошибок работы с памятью.
Попытка чтения или записи в область памяти, доступ к которой запрещен. Низкоуровневая и опасная ошибка. Причиной может быть работа с Unsafe указателями в Swift, ошибки в нативном коде (C / C++ / Obj-C), порча памяти (memory corruption). Тщательно рецензируйте весь код, использующий UnsafeRawPointer и аналоги. Запустите приложение с Address Sanitizer. Установите символьные точки останова на функции работы с памятью.
Приложение само вызвало аварийное завершение. Это самый прозрачный тип краша. Причиной может быть срабатывание fatalError(), принудительное извлечение опционала (!), неудачное выполнение assert() или precondition, ошибки валидации в Core Data. Внимательно читайте сообщение в консоли, оно часто напрямую указывает на причину. Изучите верхушку стек-трейса, чтобы найти строку вашего кода, которая инициировала остановку. Замените force unwrap на безопасные конструкции (if let, guard let).
Выполнение недопустимой инструкции процессора или срабатывание контрольной точки (trap). Причиной может быть срабатывание assertionFailure в релизной сборке, дебаг-проверки, которые сработали не в той среде, ошибки в условиях precondition. Проверьте, не активны ли строгие проверки (assert) в релизной сборке. Сравните поведение Debug и Release версий. Убедитесь, что все предположения о данных, защищенные precondition, корректны.
Приложение превысило лимит памяти, выделенный системой и было завершено. Причиной может быть кэширование больших изображений без ограничений, утечки памяти (retain cycles), удержание в памяти огромных массивов данных. Запустите Memory Graph Debugger (кнопка с тремя кругами в Xcode) для визуализации графа объектов и поиска циклов сильных ссылок. Используйте Allocations Instrument для отслеживания роста потребления памяти во времени. Внедряйте инструменты для снижения давления памяти (например, NSCache вместо словаря для изображений).
Система усыпила приложение за блокировку главного потока более чем на несколько секунд. Причиной могут быть синхронные сетевые запросы на главном потоке, декодирование большого JSON, тяжелые вычисления в SwiftUI.body. Используйте инструментарий Time Profiler для записи и анализа активности потоков. Найдите операции, блокирующие main thread. Выносите длительные задачи с Main Actor с помощью Task.detached или фоновых очередей.
Понимание типа краша превращает хаотичный поиск ошибки в целенаправленное расследование. Это экономит часы, а иногда и дни работы. Но конечная цель не просто чинить падения, а создавать код, который к ним менее склонен. Правильно интерпретировав причину краша, вы не просто исправите баг, а сделаете работу приложения стабильнее.
Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19 10❤5🔥2🙏1
@Observable в SwiftUI: почему это больше, чем замена ObservableObject.SwiftUI продолжает эволюционировать, и одним из самых значимых изменений за последнее время стало появление макроса
@Observable. Многие разработчики до сих пор используют привычный ObservableObject, не до конца понимая, что новый подход - это не просто синтаксический сахар, а фундаментальное улучшение в философии управления состоянием. Если вы все еще заставляете свои модели подчиняться протоколу ObservableObject и разбрасываете @Published, самое время разобраться, как @Observable делает код не только чище, но и эффективнее на системном уровне.Философский сдвиг - от ручного объявления к автоматическому обнаружению изменений:
Ключевое различие между двумя подходами лежит в парадигме. ObservableObject требует от вас явного объявления намерений. Вы помечаете класс протоколом, а каждое свойство, которое должно публиковать изменения - модификатором
@Published. Это императивный подход: «Я, разработчик, говорю системе, за чем именно нужно следить».@Observable реализует противоположную, декларативную философию. Вы просто помечаете класс макросом @Observable. Система на этапе компиляции анализирует ваш код и автоматически определяет, какие свойства могут изменяться и требуют наблюдения. Вы декларируете: «Это класс с наблюдаемым состоянием», а система сама решает, как за этим эффективно следить.Технические отличия - Runtime vs Compile-time наблюдение:
Этот философский сдвиг имеет прямые технические последствия для производительности и поведения.
@Published, оно через objectWillChange.send() асинхронно уведомляет всех подписчиков (ваши View) о том, что что-то в этом объекте поменялось. View затем вынуждены пересчитать свое тело, чтобы понять, изменились ли конкретные данные, которые они отображают. Это приводит к потенциально избыточным перерисовкам.@Observable (Compile-time Observation): макрос раскрывается в код, который реализует гранулярное отслеживание доступа. SwiftUI на этапе компиляции строит точные связи между конкретными свойствами модели и конкретными View, которые их используют. Когда свойство изменяется, система точно знает, какие именно View зависят от этого конкретного свойства и обновляет только их. Это устраняет лишние перерисовки и повышает производительность.Появление
@Observable - это не просто замена одного модификатора другим. Это шаг SwiftUI к более зрелой, эффективной и декларативной модели реактивности. Он переносит нагрузку с разработчика (которому больше не нужно вручную расставлять флажки для системы) на компилятор, который может оптимизировать наблюдение за состоянием с недоступной ранее точностью.ObservableObject выполнил свою историческую роль, заложив основы реактивного программирования в SwiftUI.
@Observable - это его логическое и технологическое развитие, предлагающее тот же результат с меньшими усилиями и большей эффективностью.Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM