📱
ContentBuilder - секрет ускорения проверки типов в SwiftUIНа
сессии WWDC 2026 инженеры Apple представили новую функцию SwiftUI: ContentBuilder. Он представляет собой не что иное, как ViewBuilder с более широким охватом - API, которые раньше принимали ViewBuilder, ToolbarContentBuilder, или CommandsBuilder по отдельности, теперь это один конструктор.
Apple также утверждает, что это изменение
значительно повышает производительность проверки типов. Давайте рассмотрим что же такое ContentBuilder и за счет чего достигается такая производительность.
Для начала давайте вспомним как работает
@ViewBuilder в SwiftUI:
@ViewBuildervar 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
@available(iOS 27.0, macOS 27.0, *)
public static func buildBlock(
_ content: repeat each Content
) -> TupleContent
public static func buildIf(
_ content: Content?
) -> Content?
public static func buildEither(
first: TrueContent
) -> _ConditionalContent
Обратите внимание:
ни одна из этих сигнатур не содержит Content: View
, Content: ToolbarContent
или Content: Commands
ограничений. Задача builder-а стала чисто структурной. Недавно представленный TupleContent является ключевым элементом дизайна. Его отличительная особенность заключается в том, что
он принимает различные формы в зависимости от того, что могут делать его элементы.
Другими словами, TupleContent изначально не принадлежит ни к какому домену. Это View только в том случае, если каждый элемент, который он содержит, является View. когда все его элементы являются ToolbarContent, он
является содержимым панели инструментов. Optional, _ConditionalContent, Group и ForEach используют один и тот же подход.
Таким образом, разработчик может сначала создать единую конкретную структуру:
TupleContent
Только когда сигнатура функции требует some View компилятор возвращается к проверке того, что и Text и Image соответствуют View.
Для Group новый интерфейс можно описать так:
public struct Group { ... }
extension Group {
public init(
@ContentBuilder content: () -> Content)
}
extension Group: View where Content: View {}
extension Group: ToolbarContent where Content: ToolbarContent {}
extension Group: Commands where Content: Commands {}
Для доменов ContentBuilder унифицированы - View, ToolbarContent, Commands и т. д. — Group { ... } в обычном клиентском коде теперь предпочтительнее использовать эту универсальную точку входа в сборку без ограничений по доменам. Apple решила исправить междоменные вложенные общие компоненты, такие как Group, ForEach, и Section. Сократилось время проверки типов выражений, содержащих эти деревья перегрузок.