Веб-версияОткрыть в Telegram
IiOS Broadcast

iOS Broadcast

@ios_broadcast · канал · Технологии · в индексе с 2026-04-22
3 490подписчиков
А
Андрей Зонов
Фотография
нажмите — покажем
Фотография
нажмите — покажем
16 · 1.6K ·
А
Андрей Зонов
Фотография
нажмите — покажем
🐥 Почему @MainActor и протоколы в Swift 6 могут поссориться В теории всё просто, есть протокол: protocol ImageLoader { ... } Реализация, которая работает с UI: @MainActor final class ImageLoaderImpl: ImageLoader { ... } Но Swift 6 начинает задавать неприятный вопрос: а сам протокол изолирован от Main Actor или нет? И вот тут начинается самое интересное. @MainActor на конкретной реализации не означает автоматически, что любой код, который работает с протоколом, тоже находится на Main Actor. Для компилятора протокол может использоваться совершенно независимо от конкретной реализации. В результате вполне невинный код начинает упираться в ошибки concurrency: 🟡Вызов main-actor метода из nonisolated контекста 🟡Несоответствие требований протокола и actor isolation 🟡Необходимость добавлять @MainActor туда, где раньше его вообще не было Особенно часто это всплывает при dependency injection. Например, ViewModel хранит зависимость как: let loader: ImageLoader а конкретно переданный ImageLoaderImpl является @MainActor. Swift должен гарантировать, что контракт ImageLoader сам по себе безопасен. И здесь есть несколько вариантов: ➡️ Можно сделать весь протокол @MainActor ➡️ Можно изолировать только отдельные методы ➡️ Можно использовать nonisolated, если конкретная операция действительно не зависит от Main Actor И вот последний вариант особенно важно не использовать просто для того, чтобы "заткнуть компилятор". Если метод реально работает с состоянием, которое должно жить на Main Actor, nonisolated проблему не решает. Он просто заставляет вас взять ответственность за безопасность на себя. Попробую подытожить: @MainActor — это не просто атрибут класса. Это часть контракта, и при работе через протокол этот контракт должен быть виден там, где он действительно нужен. Поэтому при проектировании Swift 6 API стоит заранее решить: 🟢Весь сервис main-actor isolated? 🟢Только часть его методов? 🟢Протокол вообще должен знать про actor isolation? 🟢Можно ли использовать dependency без Main Ac
22 · 1.2K ·
А
Андрей Зонов
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
🆓 Типобезопасные JSON в StructuredQueries Оч интересное обновление вышло у библиотеки StructuredQueries. Сама библиотека разработана Point-Free предоставляет набор инструментов, которые позволяют вам писать типобезопасные, выразительные и компонуемые SQL-выражения на языке Swift. Но данное обновление расширяет DSL на JSON и JSONB ( это тип данных, который хранит JSON-документы в оптимизированном бинарном формате). Элегантный DSL для указания типа для сериализации в таблице: @Table struct Trip: Identifiable { let id: UUID var name = "" @Column(as: Location.JSONRepresentation.self) var location: Location } Вот так будет выглядеть запрос местоположения поездки, хранящейся в столбце JSON: @Selection struct Location: Codable { var latitude = 0.0 var longitude = 0.0 } При применении макроса @Selection к Location структура типа становится видимой для builder-а запросов, и дает возможность перемещаться по JSON с помощью метода jsonExtract и привычного пути к ключу в Swift: Trip.where { $0.location .jsonExtract(\.longitude) < 0 } // Превращается в SQL SELECT … FROM "trips" WHERE json_extract( "trips"."location", '$."longitude"') < 0 Это означает, что вы получаете безопасность схемы для столбцов вашей таблицы, для полей внутри ваших JSON-данных и для извлекаемых значений. И эти выражения можно использовать в любом месте запроса: where, select, order в полях и т. д. Вы также можете обновлять данные в формате JSON непосредственно в базе данных, не загружая их в память, используя jsonSet, jsonInsert, jsonAppend, jsonRemove и jsonReplace: Profile.update { $0.author = $0.author .jsonSet(\.name, "Blob") } // превращается в UPDATE "profiles" SET "author" = json_set( "profiles"."author", '$."name"', 'Blob' ) Profile.update { $0.tags = $0.tags .jsonAppend("new") } // превращается в UPDATE "profiles" SET "tags" = json_insert( "profiles"."tags", '$[#]', 'new' ) Не сказал бы что работа с SQLite напрямую часто требуется, но во-первых это
11 · 1.2K ·
А
Андрей Зонов
Фотография
нажмите — покажем
Фотография
нажмите — покажем
🐥 @FocusState в SwiftUI Давайте базовую тему - фокус в SwiftUI.  @FocusState позволяет хранить состояние фокуса прямо в SwiftUI и управлять им из кода. Например, можно описать поля формы: 🟡имя🟡email🟡пароль. После чего можно переключать фокус между ними после ввода. Это можно сделать через enum: enum Field { case name, email, password } А затем привязать его к focused(...) В итоге логика становится довольно читаемой: 🟢открыть экран и сразу поставить фокус на поле 🟢нажать далее и перейти к следующему 🟢после ошибки вернуть пользователя к нужному полю 🟢скрыть клавиатуру, сбросив focus в nil @FocusState лучше воспринимать именно как состояние UI, а не как часть бизнес-логики. Не нужно тащить информацию о том, какое поле сейчас активно, в модель или сервис. Фокус относится к интерфейсу. Но не стоит использовать несколько независимых @FocusState, когда все поля относятся к одной форме. Обычно один enum для всей формы получается проще и предсказуемее. Магия @FocusState лежит не только в упрощении работы с формами, это подход по делегированию поведения системе. Это особенно актуально, если интерфейс по-настоящему кросплатформенный и работает не только на iOS/iPad, но и на mac или даже Apple TV. Вместо becomeFirstResponder, ссылок на UIKit и ручного управления клавиатурой достаточно описать: какое поле сейчас должно быть в фокусе и дальше SwiftUI сам занимается остальным.
13 · 1.3K ·
А
Андрей Зонов
Фотография
нажмите — покажем
📱 Как заставить SwiftUI делать красивые переносы Обычно статьи про текст рассказывают то как быстро и точно рассчитать размер контейнера, но тут более редкая проблема - некрасивые переносы слов. Случай, когда текст красиво выглядит почти на всех размерах экрана, а потом на каком-нибудь iPhone последняя строка внезапно состоит из одного-двух слов. Понятная логика, перенести это слово на предыдущую строку не понятно как описать без костылей вставки переносов в исходный текст, ведь стандартный Text не даёт нормального контроля над такими переносами. В статье интересный подход: использовать AttributedString и управлять правилами переноса через paragraph style. В частности, можно задать lineBreakStrategy и использовать .pushOut, чтобы SwiftUI старался не оставлять слишком короткую последнюю строку. Получается довольно приятная штука: 🟢не нужно вручную вставлять \n 🟢не нужно делать разные варианты текста для разных устройств 🟢перенос остаётся адаптивным И это хороший пример того, как иногда проблема SwiftUI находится не в самом Text, а уровнем ниже, в типографике и AttributedString. При этом есть важный нюанс: Не стоит пытаться запретить любые короткие строки. Иногда перенос действительно является правильным, а попытка любой ценой выровнять текст только ухудшит результат. Статья меня зацепила даже не самой идеей решения, а концепцией: типографику тоже можно сделать частью layout-поведения. И если текст выглядит странно только на некоторых размерах экрана, возможно, не нужно добавлять ещё один frame(). Сначала стоит посмотреть, какие правила переноса вообще используются.
26 · 1.3K ·
А
Андрей Зонов
Фотография
нажмите — покажем
📱 ContentBuilder - секрет ускорения проверки типов в SwiftUI На сессии WWDC 2026 инженеры Apple представили новую функцию SwiftUI: ContentBuilder. Он представляет собой не что иное, как ViewBuilder с более широким охватом - API, которые раньше принимали ViewBuilder, ToolbarContentBuilder, или CommandsBuilder по отдельности, теперь это один конструктор. Apple также утверждает, что это изменение значительно повышает производительность проверки типов. Давайте рассмотрим что же такое ContentBuilder и за счет чего достигается такая производительность. Для начала давайте вспомним как работает @ViewBuilder в SwiftUI: @ViewBuilder var content: some View { Text("Hello") Image(systemName: "star") } И SwiftUI как будто просто понимает, что делать с несколькими View, но никакой магии тут нет. @ViewBuilder это result builder, то есть специальный механизм Swift, который превращает декларативный код в обычные вызовы методов builder'а. То есть когда мы пишем: if isLoading { ProgressView() } else { ContentView() } SwiftUI не исполняет это как обычный if, а возвращающий разные типы. ViewBuilder строит из этого единую структуру, которую затем SwiftUI использует для своего view tree. За счет этого body может содержать несколько View, хотя обычная функция не может просто так вернуть несколько разные типы. ViewBuilder не является чем-то исключительно SwiftUI-ным, это обычный result builder из Swift. Поэтому похожий подход можно использовать и для собственных DSL. За счет чего же достигается ускорение проверки типов? Помимо typealias указания на ViewBuilder, реальным фактором повышения производительности стало изменение способа объявления API. Выигрыш обусловлен тем, что SwiftUI переработал инициализаторы общих компонентов и выходные типы builder-а. public static func buildBlock<Content>( _ content: Content ) -> Content @available(iOS 27.0, macOS 27.0, *) public static func buildBlock<each Content>( _ content: repeat each Content ) -> TupleContent<repeat each
18 · 993 ·
А
Андрей Зонов
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
🐥 Data Detector в iOS 26: ссылки прямо из обычного текста В iOS 26 Apple добавила новый фреймворк - DataDetector, который умеет находить в тексте полезные сущности: ссылки, телефоны, адреса, даты и другие данные. Раньше для такого сценария часто приходилось самостоятельно разбирать строку, искать regex'ами URL и телефоны, а потом превращать найденные куски в ссылки. Совсем олдскульные разработчики вспомнят про NSDataDetector, но его далеко не так просто адаптировать для прямой работы со строкой в Swift. DataDetector умеет работать не только с обычным String, но и с AttributedString, добавляя найденным данным соответствующие атрибуты. То есть текст: Позвони мне завтра в 15:00 или посмотри https://t.me/ios_broadcast может автоматически превратиться в интерактивный текст с распознанными сущностями. Особенно полезно для: 🟢чатов 🟢заметок 🟢email 🟢документов 🟢preview пользовательского текста Это системный механизм, который знает гораздо больше о том, что именно находится в тексте. Основной плюс системного подхода: Data Detector учитывает локаль и системные форматы. Это сильно поможет при международном распространении приложения. Телефон, дата или адрес могут выглядеть совершенно по-разному в разных странах, и поддерживать все эти варианты самостоятельно довольно быстро становится неприятно. Но DataDetector не превращает любой Text автоматически в интерактивный. Это именно инструмент для анализа текста и добавления metadata. А уже UI-слой решает, как эти данные отображать и что делать по нажатию. Очень радует что это не SwiftUI компонент для работы с текстом, а небольшой нормальный системный фреймворк - кирпичик. Он закрывает одну раздражающую задачу.
26 · 1.2K ·
А
Андрей Зонов
Фотография
нажмите — покажем
Фотография
нажмите — покажем
Фотография
нажмите — покажем
📱 Как тестировать навигацию в SwiftUI Навигацию обычно тестируют примерно никак. Еще 3 года назад я рассказывал как можно в UIKit описывать навигацию декларативно и тестировать ее (Декларативная навигация в iOS-приложении). В SwiftUI тенденция тестировать навигацию, к моему удивлению, до сих не стала повсеместной. Хотя почти у всех есть NavigationStack, несколько маршрутов, deep links, sheet, ошибки и авторизация, и если подумать - навигация уже является частью бизнес-логики. В статье Azam Sharp интересный подход: не тестировать сам NavigationStack. Вместо этого вынести решение по навигации в отдельную логику. Например, вместо: if isLoggedIn { navigationPath.append(.home) } else { navigationPath.append(.login) } сделать так, чтобы ViewModel или router решал: destination = .home или: destination = .login А SwiftUI уже занимается отображением этого состояния. Тогда тесту вообще не нужен UI. Можно проверить: 🟢авторизованный пользователь → .home 🟢неавторизованный → .login 🟢после сохранения → .details 🟢ошибка → .error 🟢deep link → правильный маршрут Основная идея - сделать навигацию обычным состоянием приложения. Например: enum Route: Hashable { case home case profile case settings } А NavigationStack просто отображает текущий маршрут. Это особенно хорошо работает с NavigationPath, потому что сам path можно рассматривать как данные. Изменился path → изменился navigation state → SwiftUI обновил UI. после такого сдвига парадигмы тестировать становится намного проще. При этом не обязательно сразу строить огромный Router. Для небольшого приложения вполне может хватить @State или @Observable-модели. После того как Navigation становится обычными данными, тестировать становится намного проще. Ну а если вам идея понравится, советую пойти дальше и посмотреть мой доклад, фреймворк отлично подходит и для SwiftUI
23 · 1.3K ·

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Чего мы не делаем · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем