На iPhone Duo элементы управления навигацией, действия тулбара и вкладки могут перемещаться в общую вертикальную панель, расположенную по краю экрана. Это освобождает больше пространства для контента. Приложения, собранные с iOS 27.1 SDK, получают эту адаптацию через стандартные контейнеры: NavigationStack, NavigationSplitView и TabView. Мы по-прежнему объявляем действия тулбара в привычных местах, а SwiftUI решает, как их показать в текущем контексте.
Управление осью элемента:
SwiftUI использует содержимое элемента, чтобы решить, может ли он переместиться в вертикальную панель. Стандартные элементы с символами участвуют автоматически. Текстовые элементы и сложное кастомное содержимое по умолчанию остаются горизонтальными. Модификатор axisBehavior(_:) позволяет переопределить это поведение для отдельных элементов тулбара.
Например можно создать меню с кастомной меткой, которая объединяет фигуру и текст. С автоматическим поведением SwiftUI оставит это меню в горизонтальной панели. Если метка достаточно маленькая, чтобы поместиться в вертикальную панель, можно применить .axisBehavior(.verticalPreferred) к элементу тулбара. Тогда меню присоединится к другим элементам вдоль правого края.
Для кастомного содержимого, которому нужно больше горизонтального пространства, можно использовать .horizontalOnly, чтобы оставить элемент в горизонтальной панели. Это также полезно, когда содержимое элемента меняется и мы хотим, чтобы его ось оставалась стабильной.
Адаптация содержимого под расположение панели:
Иногда нужно, чтобы кастомное содержимое тулбара подстраивалось под расположение панели. Для этого есть новое значение окружения toolbarVerticalEdge. Оно говорит, с какой стороны система разместит вертикальную панель: слева или справа. Если вертикальная панель не используется, значение равно nil - и тогда можно выбрать горизонтальную компоновку.
Допустим, у нас есть элемент тулбара с настройкой .axisBehavior(.verticalPreferred), то есть он может переместиться в вертикальную панель. Его метка состоит из фигуры и текста. Мы хотим, чтобы в горизонтальной панели они стояли рядом, а в вертикальной - друг под другом.
Для этого проверяем toolbarVerticalEdge. Если он равен nil, располагаем элементы горизонтально. Если нет - вертикально.
Отключение вертикальных панелей:
Для интерфейсов, которым нужно больше горизонтального пространства, можно отказаться от вертикальных панелей с помощью модификатора toolbarVerticalBehavior(_:). Установка в disabled возвращает содержимое панели в стандартные горизонтальные верхнюю и нижнюю панели и восстанавливает горизонтальное расположение статус-бара.
Например в списке, где единственное действие тулбара - кнопка закрытия, вертикальная панель оставляет меньше ширины для контента. Если применить модификатор внутри списка, он управляет панелями списка независимо от представляющего представления.
Внутри окна SwiftUI использует поведение панели, указанное самым верхним представлением в NavigationStack, выбранной вкладкой в TabView или самой правой колонкой в NavigationSplitView.
Установка разного поведения панели на представлениях в одном стеке навигации может заставить панели переключаться между горизонтальным и вертикальным расположением при навигации. Apple рекомендует сохранять поведение согласованным, а не менять его часто во время навигации или в ответ на временное состояние представления.
iPhone Duo приносит новые API для работы с тулбарами. axisBehavior(_:) управляет осью отдельного элемента. toolbarVerticalEdge показывает, используется ли вертикальная панель. toolbarVerticalCompressionBehavior(_:) задает приоритет между вкладками и действиями. toolbarVerticalBehavior(_:) позволяет отключить вертикальные панели там, где они мешают. Эти инструменты дают контроль над тем, как интерфейс адаптируется к складному устройству. Но Apple рекомендует не менять поведение слишком часто. Лучше один раз определить, как должны выглядеть панели, и придерживаться этого решения.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13 6🔥3❤2🙏1👀1
Picture-in-Picture - системная функция iOS, которая позволяет воспроизводить видео в отдельном плавающем окне поверх других приложений. Пользователь может свернуть приложение, продолжив смотреть контент в компактном окошке. Для разработчика видеосервиса это отдельный механизм со своей инфраструктурой, жизненным циклом и ограничениями.
Что такое PiP:
Технически PiP - это не просто маленькое видео в углу. Это сквозной системный механизм. Окно PiP не принадлежит приложению в привычном смысле - оно управляется системой и продолжает жить, даже когда пользователь перешел на рабочий стол. Функция появилась на iPad в iOS 9, но для iPhone стала общедоступной с iOS 14. С этого момента фоновое воспроизведение видео в маленьком окошке стало стандартом для уважающих себя видеосервисов.
Подготовка и запуск:
Основной инструмент - класс AVPictureInPictureController. Создать его можно двумя способами: передать ссылку на AVPlayerLayer или использовать contentSource.
let pipController = AVPictureInPictureController(playerLayer: playerLayer)
Либо:
let contentSource = AVPictureInPictureController.ContentSource(playerLayer: playerLayer)
let pipController = AVPictureInPictureController(contentSource: contentSource)
Настройка AVAudioSession:
Чтобы система разрешила запускать видео в фоне, необходимо правильно настроить AVAudioSession. Без этого startPictureInPicture() просто не сработает.
do {
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playback, mode: .moviePlayback)
try session.setActive(true)
} catch {
print("Failed to configure AVAudioSession: \(error)")
}
Почему PiP может не запуститься:
Есть две частые проблемы:
Отслеживание состояний:
Для отслеживания жизненного цикла PiP нужно реализовать протокол AVPictureInPictureControllerDelegate. Он включает методы WillStart, DidStart, FailedToStart, WillStop, Restore и DidStop. Особый интерес представляет Restore. Он вызывается, когда пользователь возвращается из PiP в приложение. В этом методе нужно восстановить UI плеера и вызвать completionHandler(true).
func pictureInPictureController(
_ pictureInPictureController: AVPictureInPictureController,
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void
) {
self.playerView.isHidden = false
completionHandler(true)
}
Для автоматического запуска PiP при свайпе на главный экран можно использовать флаг canStartPictureInPictureAutomaticallyFromInline.
Picture-in-Picture - мощный инструмент, который улучшает пользовательский опыт. Но для стабильной работы критически важно правильно настроить аудиосессию и Background Modes, грамотно управлять памятью контроллера и использовать contentSource для бесшовного переключения видео. Подкапотный механизм сложнее, чем кажется. AVKit взаимодействует с системным фреймворком Pegasus, который управляет окном PiP. Понимание этой архитектуры помогает избегать типичных ошибок, а работу сделать стабильной и надежной.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤5🔥2🙏1 1
Forwarded from Flutter & Dart | Мобильный трудоголик
Разработка с ИИ-агентами за последний год сделала большой шаг вперед. Но многие все еще используют одного агента для всего: архитектуры, тестов, отладки. На маленьких задачах это работает. Когда проект становится сложнее, агент теряет контекст, начинает галлюцинировать и допускать ошибки.
Недавно в блоге Flutter вышла статья, в которой автор экспериментирует с мультиагентным подходом. Вместо одного универсального агента он создал команду из четырех специализированных ролей: архитектор, тестировщик, кодер и координатор. Задача была не простая: портировать популярную Python-библиотеку python-statemachine в статически типизированный Dart-пакет без использования рефлексии (dart:mirrors во Flutter запрещены).
Как устроена мультиагентная команда:
Основа эффективной агентной команды - четко определенные роли с ограничениями на то, что агент может делать.
Автор создал общий воркфлоу-скилл (tdd-dart-workflow) с правилами TDD и разрешениями, а также четыре ролевых скилла:
Строгое разделение ролей не дает ни одному агенту изменять и тесты и код одновременно. Координатор получает только краткий отчет о завершении задачи. Это создает когнитивный файрвол: история проб и ошибок суб-агента отбрасывается после завершения его задачи. Контекст координатора остается чистым, без переполнения токенами.
Для предотвращения гонок и непроверенных коммитов доступ к файловой системе ограничен:
Статическая типизация и TDD:
В динамических языках TDD начинается с падающего теста, который выбрасывает рантайм-ошибку. В статических языках тест для несуществующего метода не скомпилируется, и тест-раннер даже не запустится.
Решение: сначала тестировщик пишет тесты по спецификации. Затем кодер создает скелеты в lib/src/ с заглушками, которые возвращают dummy-значения или бросают UnimplementedError. Когда скелет удовлетворяет компилятору, координатор запускает dart analyze && dart test и проверяет, что тесты падают по правильным причинам. Комментарии отделяют временные заглушки от постоянных тестовых утилит.
Результат:
Итоговый Dart-пакет state_machine сохранил полную функциональность оригинальной Python-библиотеки. Кодер реализовал fluent-билдеры для поддержки Dart-синтаксиса.
Мультиагентный подход с разделением ролей работает для Flutter-разработки. Он предотвращает потерю контекста, уменьшает галлюцинации и повышает качество кода. Когнитивный файрвол позволяет сохранять чистоту контекста координатора, отбрасывая историю суб-агентов после завершения задач.
Но подход не без проблем. Необходимы четкие роли, ограничения на запись и навыки, описывающие процессы. Требуется постоянная доработка скиллов по мере возникновения новых ситуаций.
В итоге автор получил не просто Dart-пакет, а набор переиспользуемых навыков для мультиагентной разработки. Вместо одного агента, который пытается делать все, команда из четырех специализированных агентов работает эффективнее. И это, вероятно, будущее Flutter-разработки с ИИ.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯10❤5👍3🔥1
В iOS 27.1 появился модификатор .onHingeChange, который позволяет получить текущее состояние угла раскрытия iPhone Duo и использовать его для управления анимацией, звуком или другими эффектами.
Пример - изменение высоты тона гитары в зависимости от угла раскрытия устройства:
struct InstrumentView: View {
@State private var pitchBend: Double = 0
var body: some View {
GuitarView(pitchBend: pitchBend)
.onHingeChange { _, context in
if let hinge = context.hinge, hinge.status == .partiallyOpen {
pitchBend = calculatePitchBend(angle: hinge.angle)
} else {
pitchBend = 0
}
}
}
private func calculatePitchBend(angle: Angle) -> Double { ... }
}
Когда устройство частично открыто, угол передается в метод, который вычисляет значение изменения тона. В остальных состояниях значение сбрасывается в ноль.
Где еще это может быть полезно:
Угол раскрытия можно использовать не только для звука. Например, для управления громкостью: чем шире раскрыто устройство, тем громче звук. Или для анимации: персонаж на экране может наклоняться в зависимости от положения шарнира. Или для игр: угол становится дополнительным управляющим элементом, который не требует касания экрана. Все, что угодно, где физическое положение устройства может влиять на поведение приложения.
.onHingeChange дает разработчикам доступ к состоянию шарнира iPhone Duo. Это открывает новые сценарии для интерактивных приложений: музыкальных инструментов, игр, обучающих программ. Угол раскрытия становится еще одним способом взаимодействия с устройством, наравне с касанием, жестами и голосом.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12 7🔥3❤2🙏1
В Swift 6.4 появилась новая диагностика, которая помогает ловить неочевидные ретейн циклы. Предупреждение срабатывает, когда вложенное замыкание выполняет слабый захват, а родительское замыкание при этом неявно захватывает объект как сильную ссылку.
На первый взгляд это может показаться избыточным. Зачем указывать слабый захват дважды? Но на практике это очень полезное предупреждение, которое помогает избежать распространенного типа ошибок управления памятью.
В чем суть проблемы:
Рассмотрим пример. Внутри замыкания, переданного в loadNearbyFriends, используется weak self. При этом родительское замыкание не захватывает self явно.
timer = Timer.scheduledTimer(
withTimeInterval: 3,
repeats: true,
block: { [service] _ in
service.loadNearbyFriends { [weak self] friends in
self?.friends = friends
}
}
)
При компиляции в Swift 6.3 это код не вызывает предупреждений. Но на самом деле здесь возникает ретейн цикл. Хотя мы не захватывали self явно, компилятор неявно вставляет сильный захват self в родительское замыкание.
В результате Timer захватывает self, который удерживает объект через свойство timer. Классический ретейн цикл.
Что изменилось в Swift 6.4:
Теперь при компиляции этого кода появляется предупреждение:
'weak' ownership of capture 'self' differs from implicitly-captured strong reference in outer scope
Предупреждение явно указывает на проблему. И это гораздо лучше, чем молчаливый ретейн цикл, который может привести к утечке памяти.
Как исправить:
Есть несколько способов:
block: { [weak self, service] _ in
service.loadNearbyFriends { friends in
self?.friends = friends
}
}
block: { [weak self] _ in
guard let self else { return }
logScanningDidStart()
service.loadNearbyFriends { [weak self] friends in
self?.friends = friends
}
}
Task { [self] in
guard await !cache.isValid else { return }
service.loadNearbyFriends { [weak self] friends in
self?.friends = friends
}
}
В этом случае сильный захват безопасен, потому что после проверки кеша и вызова loadNearbyFriends замыкание будет освобождено.
Swift 6.4 добавляет предупреждение для слабого захвата во вложенных замыканиях, когда родительское замыкание неявно захватывает объект как сильную ссылку.
Это помогает ловить неочевидные ретейн циклы, которые раньше оставались незамеченными. Диагностика требует большей явности в коде, но это оправдано. Ретейн циклы - слишком частая проблема, чтобы оставлять их без внимания.
Swift продолжает развиваться в сторону безопасности. Новые предупреждения помогают писать более надежный код и избегать типичных ошибок.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
Apple опубликовала требования к приложениям для iPhone Duo. Складное устройство выходит 23 октября 2026 года. Но уже сейчас понятно: поддержка станет обязательной. С апреля 2027 года все приложения, отправляемые в App Store, должны включать скриншоты для iPhone Duo. Без этого модерацию не пройти.
Что уже известно:
iPhone Duo появится у покупателей 23 октября. Первые полгода наличие адаптированной версии не обязательно. Но с апреля 2027 правила меняются. Apple требует, чтобы любое приложение, собранное с iOS 27.1 SDK и новее, предоставляло снимки экрана для iPhone Duo.
Уже сейчас можно подготовиться. Для этого нужно пересобрать приложение в Xcode 27.1. В Device Hub можно посмотреть, как приложение ведет себя на iPhone Duo во всех положениях и ориентациях.
Что нужно сделать:
Apple описывает три шага:
Зачем это Apple:
Ситуация напоминает историю с Vision Pro. У очков Apple не сложилась большая база приложений. Одна из причин - высокая цена устройства и ограниченная аудитория. Теперь Apple не хочет повторения. Компания заранее обязывает разработчиков готовить приложения под новое устройство, даже если пользователей будет немного.
Логика понятна. Если приложений нет, устройство не покупают. Если устройство не покупают, приложений не появляется. Apple пытается разорвать этот круг административными методами.
Но есть вопрос: сколько людей реально будет пользоваться iPhone Duo? Складные устройства пока остаются нишевым продуктом. Даже если Apple выпустит хорошее устройство, аудитория может оказаться небольшой. И разработчики будут тратить время на адаптацию под платформу, которая не приносит пользователей.
С апреля 2027 поддержка iPhone Duo становится обязательной. Apple требует скриншоты для нового устройства при отправке приложений в App Store. Подготовиться можно уже сейчас: пересобрать в Xcode 27.1, протестировать, обновить материалы страницы в App Store Connect.
Но остается открытым вопрос: оправданы ли эти усилия? Если iPhone Duo повторит судьбу Vision Pro и останется нишевым устройством, разработчики потратят время на адаптацию под платформу без пользователей. Apple явно рассчитывает на обратное. Но рынок покажет, кто прав.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯12👍8👀3❤1🤔1
Forwarded from Кот Денисова
В ИТ недостаточно просто уметь писать код. Рынок меняется, технологии устаревают, приоритеты сдвигаются. Без умения быстро перестраиваться даже опытный специалист рискует остаться без работы.
Технологии и рынок не стоят на месте:
Инструменты, языки и подходы обновляются постоянно. Еще недавно все искали специалистов под один стек, сегодня - под другой, а завтра требования снова изменятся. То, что вы выучили два года назад, уже может считаться устаревшим. Чтобы оставаться востребованным, нужно уметь перестраиваться и не цепляться за привычный стек. Следить за тем, что появляется нового в индустрии, изучать свежие инструменты и технологии, а главное - понимать, что технологии и фреймворки это всего лишь инструменты для решения определенных проблем и задач, а не религия. Смена подхода - не трагедия, а естественный процесс. И тот, кто замыкается на одной технологии, быстро оказывается за бортом.
Когда все идет не по плану:
В разработке редко все идет по плану, особенно если план расписан на несколько лет вперед. Прод падает, заказчик передумал, бизнес меняет направление. Тот, кто не выдерживает изменений, паникует и мешает всей команде, вылетит в первую очередь. Нужно уметь быстро переключаться между задачами без потери контекста, не паниковать, когда ужесточают сроки или неожиданно меняют ТЗ и находить новые способы решения задачи, когда старые перестали работать.
Рынок меняется каждый год:
Еще недавно все искали специалистов под один стек, сегодня - под другой. Завтра требования снова изменятся. Тот, кто замыкается на одной технологии, быстро оказывается за бортом. Нужно понимать, что инструменты - это всего лишь инструменты, а не религия, и спокойно переучиваться, когда рынок этого требует.
Когда задач больше, чем времени:
Иногда объем работы зашкаливает, требования расплывчаты, а информации катастрофически не хватает. В такие моменты умение перестраиваться помогает не сломаться. Нужно уметь принимать решения в условиях неполной информации, не выгорать при авралах и переработках и сохранять эффективность даже в полном хаосе.
Умение адаптироваться - это не хаотичность и не отсутствие плана. Это способность сохранять эффективность, когда вокруг все меняется. Технологии устаревают, приоритеты сдвигаются, рынок перестраивается. Тот, кто умеет быстро перестраиваться, остается востребованным. А кто нет - быстро отстает и выгорает.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12💯7❤3🗿2🔥1🙏1
SwiftUI-превью часто начинаются с простого кода. Но со временем в них появляется повторяющаяся настройка. Нужно создать временное хранилище данных, заполнить его тестовыми записями, передать это хранилище в представление. И так для каждого превью.
PreviewModifier решает эту проблему. Он позволяет вынести настройку в одно место и переиспользовать ее в нескольких превью.
Что такое PreviewModifier:
PreviewModifier - это API для превью, представленный в Xcode 16. Он разделяет настройку зависимостей и объявление
#Preview.Модификатор может создавать общий контекст и применять его к содержимому превью:
struct SampleDataPreviewModifier: PreviewModifier {
static func makeSharedContext() throws -> ModelContainer {
let configuration = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try ModelContainer(for: Item.self, configurations: configuration)
let context = container.mainContext
context.insert(Item(title: "Milk"))
context.insert(Item(title: "Coffee"))
context.insert(Item(title: "Bread"))
try context.save()
return container
}
func body(content: Content, context: ModelContainer) -> some View {
content.modelContainer(context)
}
}
Превью остаётся сфокусированным на представлении:
#Preview(traits: .modifier(SampleDataPreviewModifier())) {
ShoppingListView()
}
Создание общего контекста:
Модификатор, которому нужны общие данные, реализует метод makeSharedContext(). Он создает значение, которое потом применяется к превью.
Контекст может содержать временное хранилище данных, мок-сервисы, тестовые данные, контейнер зависимостей, данные из локального файла. Метод поддерживает асинхронную работу и распространение ошибок.
Система превью кеширует возвращенный контекст и передает его каждому превью, использующему модификатор того же типа. Это избавляет от повторной настройки.
Контекст общий, поэтому он подходит для зависимостей и начальных данных, но не для изменяемого состояния конкретного превью.
Применение контекста:
SwiftUI передает подготовленный контекст в метод body модификатора.
func body(content: Content, context: AppDependencies) -> some View {
content
.environment(context.session)
.environment(context.apiClient)
}
content - это представление, возвращенное
#Preview. Метод может применять модификаторы, внедрять значения окружения, подключать контейнер.Когда несколько зависимостей связаны, отдельный тип контекста помогает их организовать.
struct AppDependencies {
let session: SessionModel
let apiClient: MockAPIClient
}
Переиспользуемый трейт:
Использовать .modifier(...) напрямую можно. Но кастомный трейт делает повторяющиеся превью короче.
extension PreviewTrait where T == Preview.ViewTraits {
@MainActor
static var sampleData: Self {
.modifier(SampleDataPreviewModifier())
}
}
Теперь модификатор применяется по имени:
#Preview(traits: .sampleData) {
ShoppingListView()
}
В большом проекте можно определить несколько сфокусированных окружений:
#Preview(traits: .emptyDatabase) {
ShoppingListView()
}
#Preview(traits: .authenticatedUser) {
ProfileView()
}
Каждый трейт должен описывать конкретный сценарий, а не становиться единым контейнером для всех зависимостей приложения.
PreviewModifier создает четкую границу между настройкой превью и его содержимым. Он уменьшает дублирование конфигурации, поддерживает асинхронную подготовку и позволяет системе превью делить дорогой контекст между несколькими превью.
Это особенно полезно для SwiftData, моковых зависимостей и единообразных окружений превью в большом проекте. Вместо повторения одного и того же кода в каждом превью вы настраиваете контекст один раз и переиспользуете его.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
На iPhone Duo углы экрана могут быть асимметричными. Форма устройства такова, что радиусы на разных углах отличаются: где-то скругление больше, где-то меньше. Для разработчика это означает, что жестко заданные значения cornerRadius больше не работают - они не совпадут с реальной формой устройства.
Concentricity API, появившиеся в iOS 26, решают эту проблему. Они позволяют кастомным формам подстраиваться под реальные радиусы углов устройства или контейнера, а не использовать фиксированные значения.
Что такое ConcentricRectangle:
ConcentricRectangle - это фигура в SwiftUI, которая создает прямоугольник, вписанный в форму контейнера. Его углы могут быть концентрическими относительно углов контейнера. Это значит, что радиус угла вычисляется автоматически, исходя из того, где находится представление и какая форма у контейнера.
Проще говоря, если ваш интерфейс находится внутри другого представления с закругленными углами, ConcentricRectangle сам подберет радиус так, чтобы углы совпадали. Не нужно вручную высчитывать значения или подставлять константы.
Как правильно использовать:
Базовый пример выглядит так:
ConcentricRectangle()
.fill(Color.green)
.padding(8.0)
.ignoresSafeArea()
По умолчанию каждый угол вычисляется индивидуально, концентрически относительно контейнера. Если нужно задать минимальный радиус, чтобы угол не стал квадратным, используется .concentric(minimum: 12.0).
Можно комбинировать стили: один угол концентрический, другой фиксированный, третий - квадратный. Например:
ConcentricRectangle(
topLeadingCorner: .concentric(minimum: 12.0),
topTrailingCorner: .fixed(24.0),
bottomLeadingCorner: .concentric,
bottomTrailingCorner: .fixed(0.0)
)
Это дает полный контроль над каждым углом отдельно.
На iPhone Duo углы экрана асимметричны, и жестко заданные радиусы здесь не работают. ConcentricRectangle из iOS 26 решает эту проблему: он автоматически подстраивает углы под форму устройства или контейнера.
Для приложений, которые хотят выглядеть аккуратно на новом складном устройстве, это не просто удобство, а необходимость. Concentricity API - правильный инструмент для работы с углами на iPhone Duo.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥5🤝3❤1 1
Forwarded from Кот Денисова
Многие сейчас рассуждают так: зачем учить фреймворки, если нейросеть сгенерирует любой код по промпту? Звучит убедительно, особенно на фоне успехов современных LLM. Можно действительно собрать рабочий интерфейс, почти не вникая в детали.
Но вопрос в другом. Не в том, можно ли, а в том, сколько это будет стоить. По времени, деньгам на токены и нервам.
Знание технологии меняет подход к работе с ИИ:
Когда разработчик знаком с технологией, он лучше продумывает архитектуру и ключевые моменты заранее. ИИ становится мощным ускорителем: генерирует шаблонный код, дописывает рутину, экономит часы. Все это происходит быстро и предсказуемо.
А если разработчик плавает в технологии, процесс выглядит иначе. Он тратит больше токенов, потому что приходится переделывать одно и то же. Итераций становится больше. Итоговый код часто получается неоптимальным или даже ошибочным. Просто потому, что трудно объяснить нейросети то, чего не понимаешь сам.
ИИ пишет плохо? Возможно, проблема в контексте:
Часто можно услышать, что нейросети генерируют плохой код. Но причина чаще не в модели, а в том, как с ней работают. Без указания версии библиотек, требований к архитектуре, ограничений и структуры проекта модель будет гадать.
С ИИ нужно уметь работать. Есть множество техник, которые большинство пользователей игнорируют. Тех, кто жалуется на плохие результаты, обычно объединяет одно: они не дают модели достаточно контекста. А потом удивляются, почему результат их не устраивает.
Вайбкодинг - это не замена пониманию:
Можно нагенерировать работающее приложение, вообще не разбираясь в технологии. Но качество такого подхода падает по мере роста сложности. Для демо-проекта - возможно. Для реального продукта - нет.
Вот несколько моментов, которые стоит учитывать:
ИИ - это мощный инструмент, который ускоряет разработку. Но он не отменяет необходимости в фундаментальных знаниях. Можно навайбкодить демо-проект без понимания технологии. Но чтобы работать быстро, предсказуемо и качественно - база обязательна. Знание технологии меняет все: вы тратите меньше токенов, получаете более чистый код и чувствуете себя увереннее.
ИИ не заменяет инженера. Он превращает хорошего инженера в быстрого и продуктивного специалиста. А плохого в того, кто быстро генерирует плохой код и вечно правит баги.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14💯7👀2🗿2❤1🤝1
This media is not supported in your browser
VIEW IN TELEGRAM
В симуляторе iPhone Duo появилась возможность точно управлять углом раскрытия устройства. Если зажать клавишу Option ⌥, откроется слайдер, с помощью которого можно плавно задать положение шарнира. Это позволяет проверить, как интерфейс ведет себя при разных углах, а не только в фиксированных состояниях вроде открытого или закрытого.
Apple предусмотрела возможность точной настройки угла раскрытия iPhone Duo прямо в симуляторе Xcode 27.1. Это позволяет тестировать адаптивный интерфейс на промежуточных положениях, а не только в фиксированных состояниях.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤8 3🔥2💯1👀1
On-Demand Resources позволяют уменьшить начальный размер приложения. Вместо того чтобы хранить все ресурсы в бинарнике, iOS скачивает их из App Store, когда они действительно нужны. Это работает для изображений, звуков, моделей машинного обучения, игровых уровней и других данных.
Но механизм можно применить и иначе. С его помощью можно вынести из бинарника конфигурацию и токены. Это не сделает приложение неуязвимым, но усложнит статический анализ и реверс-инжиниринг.
Как это работает:
В настройках таргета нужно включить опцию Enable On Demand Resources. Затем ресурсы приложения связываются с тегами в разделе Resource Tags. По этим тегам потом можно загрузить нужный набор ресурсов. Есть три типа тегов:
Обертка для работы с ресурсами:
Для удобной работы можно создать класс, который управляет загрузкой и освобождением ресурсов:
final class OnDemandResource {
private let request: NSBundleResourceRequest
init(tags: Set<String>) {
request = NSBundleResourceRequest(tags: tags)
}
func pin() async throws -> Bundle {
let isFetched = await request.conditionallyBeginAccessingResources()
if !isFetched {
try await request.beginAccessingResources()
}
return request.bundle
}
func unpin() {
request.endAccessingResources()
}
}
Метод pin запускает запрос с указанными тегами и возвращает bundle для доступа к ресурсам. Сначала проверяется, можно ли получить ресурсы сразу. Если нет - они скачиваются из App Store. Метод unpin освобождает ресурсы, чтобы система могла их выгрузить.
Пример использования:
let resource = OnDemandResource(tags: ["Config"])
let bundle = try await resource.pin()
defer { resource.unpin() }
if let config = bundle.url(forResource: "Config", withExtension: "json") {
// декодировать конфигурацию и сохранить в Keychain
}
Конфигурация загружается по тегу, декодируется и сохраняется в Keychain. После этого ресурс можно освободить.
Зачем это нужно:
Вынос токенов и конфигурации из бинарника уменьшает поверхность атаки. Статический анализ приложения становится сложнее, потому что секретов в самом файле нет.
Но важно понимать: On-Demand Resources - это не граница безопасности. После загрузки на устройство файлы не шифруются по умолчанию. Злоумышленник с доступом к устройству может их изучить. Это дополнительный слой защиты, а не единственный.
On-Demand Resources позволяют загружать ресурсы по требованию, уменьшая начальный размер приложения. Их можно использовать не только для больших файлов, но и для выноса конфигурации и токенов из бинарника.
Это повышает сложность реверс-инжиниринга, но не заменяет другие меры безопасности. После загрузки ресурсы не шифруются, и при доступе к устройству их можно изучить.
Для нового кода Apple рекомендует Background Assets. Но понимание On-Demand Resources полезно, особенно при работе с существующими проектами.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥5 3❤1👀1
На WWDC 2026 компания Apple представила ContentBuilder. Выглядит он как ViewBuilder с более широким охватом. Но главное - Apple заявляет о значительном ускорении проверки типов.
Как работает ViewBuilder:
ViewBuilder - это result builder, механизм Swift, который превращает декларативный код в вызовы методов. Когда вы пишете несколько View подряд, ViewBuilder собирает их в единую структуру:
@ViewBuilder
var content: some View {
Text("Hello")
Image(systemName: "star")
}
Это не магия SwiftUI, а обычный result builder из Swift.
В чем была проблема:
Со временем в SwiftUI добавили много сущностей: Scene, Toolbar, Commands, Table. У каждого свой result builder. А общие компоненты вроде Group, ForEach и Section получили инициализаторы для каждого из них.
Вот как выглядел Group раньше:
extension Group: View where Content: View {
init(@ViewBuilder content: () -> Content)
}
extension Group: ToolbarContent where Content: ToolbarContent {
init(@ToolbarContentBuilder content: () -> Content)
}
extension Group: Commands where Content: Commands {
init(@CommandsBuilder content: () -> Content)
}
Когда компилятор встречал Group, он не знал, какой инициализатор выбрать. Приходилось проверять все варианты. И так на каждом уровне вложенности.
Что изменилось:
Apple переработала инициализаторы и возвращаемые типы builder.
Новые методы не содержат ограничений вроде Content: View или Content: Commands.
public static func buildBlock<Content>(
_ content: Content
) -> Content
public static func buildBlock<each Content>(
_ content: repeat each Content
) -> TupleContent<repeat each Content>
Появился TupleContent. Он не принадлежит никакой сущности. Это View только тогда, когда все его элементы - View. Когда все элементы - ToolbarContent, он становится содержимым панели инструментов.
То же самое для Optional, _ConditionalContent, Group и ForEach.
Как это работает:
Раньше компилятор на каждом уровне вложенности выбирал между несколькими инициализаторами. Теперь он сначала строит структуру, а потом проверяет ее соответствие нужному протоколу.
Для Group новый интерфейс выглядит так:
public struct Group<Content> { ... }
extension Group {
public init(@ContentBuilder content: () -> Content)
}
extension Group: View where Content: View {}
extension Group: ToolbarContent where Content: ToolbarContent {}
Компилятор больше не перебирает варианты на каждом шаге. Он определяет Content, а потом Group получает нужную возможность через условное соответствие.
Что это дает:
Проверка типов стала быстрее. Особенно в местах с глубокой вложенностью Group, ForEach и Section.
Но это не значит, что весь код компилируется в разы быстрее. Ускорение касается конкретных компонентов с перегрузками. И это не влияет на производительность приложения во время работы.
ContentBuilder - это не новый result builder. Это typealias на ViewBuilder. Но за ним стоит переработка API, которая убирает лишние перегрузки и ускоряет проверку типов.
Идея простая: сначала построить структуру, потом проверить ее возможности. Это уменьшает количество вариантов, которые компилятор должен перебрать на каждом уровне вложенности.
Apple не акцентировала внимание на ContentBuilder. Для большинства разработчиков он незаметен. Но для тех, кто сталкивался с медленной компиляцией SwiftUI, это важное изменение.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥8❤2 2🙏1
Forwarded from Кот Денисова
Все больше разработчиков добавляют в резюме упоминания об ИИ-инструментах. ChatGPT, Claude, Cursor, Copilot - все это появляется в списке навыков. Но правильно ли это? И как написать о работе с ИИ так, чтобы не испортить впечатление о себе как о специалисте?
Просто перечислить инструменты - слишком просто:
Строчка «Навыки: Swift, SwiftUI, Swift Concurrency, ChatGPT, CoreData, SwiftData» выглядит странно. ChatGPT в одном ряду с технологиями - это как указать Google в списке языков программирования. В лучшем случае такой пункт проигнорируют. В худшем - решат, что кандидат не умеет отделять инструменты от профессиональных компетенций.
В вакансиях иногда прямо указывают желание видеть опыт работы с ИИ. Тогда такое упоминание может сработать как фильтр. Но это редкий случай. И даже тогда перечисление названий моделей не покажет вашего реального уровня.
Результат - показатель опыта:
Лучше выглядит опыт, описанный через результат. В разделе достижений можно написать: «Увеличил тестовое покрытие с 20% до 95% за два дня, используя Claude Code для генерации тестов». Это звучит убедительно. Во-первых, есть конкретные цифры. Во-вторых, понятен вклад кандидата. В-третьих, видно, что ИИ использовался осознанно, а не как замена головы.
Еще один хороший пример - документация. Даже не самые мощные модели хорошо справляются с задачами по документированию кода. «С помощью ИИ устранил техдолг по документации на проекте» - это тоже результат. И тоже показывает, что кандидат умеет применять инструменты для решения реальных задач.
Что писать не стоит:
Формулировка «реализовал фичу за два часа с помощью Cursor» - это красный флаг. Она создает впечатление вайб-кодера, который коммитит не читая. Даже если это не так, такая строчка читается однозначно: человек не проверяет то, что генерирует ИИ, и не понимает, что попадает в код.
Проблема еще и в том, что такие достижения создают нереалистичные ожидания у работодателя. Если кандидат написал, что сделал фичу за два часа, значит, лид может предположить, что и остальные задачи будут решаться так же быстро. А это прямой путь к неадекватным срокам и переработкам.
Если вы используете ИИ в работе - это нормально. Но в резюме важно показывать не список инструментов, а результаты. Конкретные цифры, описания задач, улучшения процессов. И главное - демонстрировать осознанное использование ИИ, а не слепое доверие к генерации.
ИИ - это инструмент, а не навык. Покажите, что вы умеете им пользоваться, а не просто знаете, что он существует. И тогда даже самый скептический лид увидит в вас не вайб-кодера, а специалиста, который эффективно применяет современные технологии.
Подписаться на канал:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6💯2❤1🔥1