@ViewBuilder — SwiftUI-da View iyerarxiyasini deklarativ qurish uchun mo'ljallangan result builder annotatsiyasidir. Apple Developer Documentation, 2024 ma'lumotlariga ko'ra, @ViewBuilder ko'p ifodali va shartli mantiqli kod blokini Swift kompilyatori uchun tushunarli bo'lgan yagona View turiga aylantiradi. Ushbu annotatsiyasiz SwiftUI-ning if/else va body-da bir nechta elementlari bilan tanish deklarativ sintaksisidan foydalanish mumkin bo'lmaydi.
Asosiy ma'lumotlar
@ViewBuilder — result builder (SE-0289) namunasini amalga oshiruvchi annotatsiya bo'lib, SwiftUI-ga deklarativ sintaksis orqali bir nechta View-ni bitta kompozitsiyada to'plash imkonini beradi. U bir nechta ifodalarni, shartli konstruktsiyalarni va ixtiyoriy qiymatlarni mos keladigan turlarga avtomatik ravishda o'raydi: TupleView, ConditionalContent, OptionalContent.
Result builder paydo bo'lishidan oldin dasturchilar elementlarni qo'lda VStack yoki HStack-ga o'rashlari va shartli mantiq uchun uchlik operatorlari yoki fabrika metodlaridan foydalanishlari kerak edi. @ViewBuilder SwiftUI sintaksisini ixcham va o'qilishi oson qildi, if/else va siklli oddiy Swift-ga o'xshash kod yozishga imkon berdi.
Swift Evolution SE-0289 ga ko'ra, result builders SwiftUI-ga bog'liq bo'lmagan umumiy mexanizmdir. @ViewBuilder bu mexanizmning implementatsiyalaridan biri bo'lib, satrlarni qurish uchun @StringBuilder va boshqa DSL-lar uchun kutubxona implementatsiyalari bilan bir qatorda. SwiftUI-da @ViewBuilder nafaqat body uchun, balki konteynerlarning yopilish parametrlari uchun ham ishlatiladi (VStack, HStack, ZStack, List).
Imperativ UIKit-da siz UIView yaratasiz, uning xususiyatlarini sozlaysiz va addSubview orqali iyerarxiyaga qo'shasiz. @ViewBuilder bilan SwiftUI-da siz qaysi View-lar ko'rsatilishini deklarativ tarzda tasvirlaysiz va SwiftUI o'zi holat o'zgarishlari asosida elementlarni yaratish, yangilash va o'chirishni boshqaradi.
Result builder — ifodalar ketma-ketligini buildBlock, buildOptional, buildEither va boshqa statik metodlar orqali bitta murakkab qiymatga aylantiruvchi Swift mexanizmidir. Kompilyator @ViewBuilder annotatsiyasini ko'rganda, kompilyatsiya jarayonida bu metodlarni kod blokiga avtomatik ravishda qo'llaydi.
@resultBuilder
struct ViewBuilder {
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)>
static func buildIf<C>(_ c: C?) -> C?
static func buildEither<T, F>(first: T) -> ConditionalContent<T, F>
static func buildEither<T, F>(second: F) -> ConditionalContent<T, F>
}
buildBlock 1 dan 10 gacha ifodani qabul qiladi va TupleView qaytaradi. Har bir arlik (ifodalar soni) buildBlock-ning o'z overloadiga ega: buildBlock<C0> dan buildBlock<C0, C1, ..., C9> gacha. Aynan shuning uchun bitta @ViewBuilder blokidagi elementlar soni 10 bilan cheklangan.
buildEither (first/second) if/else konstruktsiyalarini qayta ishlaydi. Har bir shox tegishli metodga uzatiladi va natija ConditionalContent-ga o'raladi — shoxlarning aniq turlarini yashiradigan va SwiftUI uchun yagona interfeysni ta'minlovchi tur.
SwiftUI-da body xususiyati allaqachon @ViewBuilder bilan yashirin annotatsiya qilingan — siz bu annotatsiyani kodda ko'rmaysiz, lekin kompilyator uni avtomatik ravishda qo'llaydi. Biroq, bir nechta View qaytaradigan foydalanuvchi xususiyatlari yoki yopilish parametrlari uchun annotatsiyani aniq ko'rsatish kerak.
Cheklov 1 — blokda 10 element. Bu @ViewBuilder-ning eng mashhur cheklovidir. Bir darajada 10 dan ortiq elementni ko'rsatish kerak bo'lsa, kompilyator xato beradi. Buni Group, ForEach, List yoki pastki komponentlarga bo'lish orqali yengish mumkin. Group vizual ichki joylashuvni qo'shmaydi, lekin har bir Group bitta element hisoblanadi.
struct ManyElementsView: View {
var body: some View {
Group {
Text("1"); Text("2"); Text("3")
Text("4"); Text("5"); Text("6")
Text("7"); Text("8"); Text("9")
}
Group {
Text("10"); Text("11"); Text("12")
}
}
}
Cheklov 2 — ba'zi konstruktsiyalarning qo'llab-quvvatlanmasligi. @ViewBuilder do/catch, guard, for-in (ForEachsiz) va boshqa boshqaruv konstruktsiyalarini qo'llab-quvvatlamaydi. Sikllar uchun ForEach-dan identifikatsiya qilinadigan ma'lumotlar bilan foydalaning. Xatolarni qayta ishlash uchun Result yoki ixtiyoriy qiymatlarni qabul qiluvchi alohida View-lardan foydalaning.
Cheklov 3 — disk raskadrovka qiyinligi. @ViewBuilder-dagi xatolarda kompilyator asosiy sababni topish qiyin bo'lgan uzun xabarlarni yaratadi. Odatdagi muammolar: if/else shoxlarida tur mos kelmasligi, 10 element chegarasidan oshib ketish yoki kerakli buildBlock overloadining yo'qligi.
Namuna 1: if/else orqali shartli ko'rsatish. @ViewBuilder-ning eng keng tarqalgan foydalanish stsenariysi. Uchlik operatorlari yoki fabrika metodlarisiz holatga qarab turli View-larni ko'rsatishga imkon beradi.
struct StatusView: View {
var status: LoadStatus
@ViewBuilder
var body: some View {
switch status {
case .loading:
ProgressView("Loading...")
case .loaded(let data):
DataView(data: data)
case .error(let message):
ErrorView(message: message)
}
}
}
Namuna 2: funksiya va init parametrlarida @ViewBuilder. Yopilish orqali bolaviy View-larni qabul qiluvchi qayta ishlatiladigan konteynerlarni yaratish uchun ishlatiladi. Bu kutubxonalar va UI komponentlari uchun standart namunadir.
struct SectionCard<Content: View>: View {
let title: String
@ViewBuilder let content: Content
var body: some View {
VStack(alignment: .leading) {
Text(title).font(.headline)
content
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(12)
}
}
Namuna 3: ForEach bilan kompozitsiya. @ViewBuilder ForEach bilan to'g'ri ishlaydi, ma'lumotlar massividan elementlarni dinamik generatsiya qilish imkonini beradi. Har bir ForEach elementi @ViewBuilder kontekstida bitta ifoda hisoblanadi.
Shaxsiy ViewBuilder — @ViewBuilder bilan annotatsiya qilingan, some View qaytaruvchi foydalanuvchi funksiyasi yoki xususiyatidir. Bunday funksiyalar murakkab ko'rsatish mantiqini kapsullash va uni dasturning turli qismlarida qayta ishlatish imkonini beradi.
struct FormRow<Content: View>: View {
let label: String
@ViewBuilder let content: Content
var body: some View {
HStack {
Text(label)
.frame(width: 120, alignment: .trailing)
content
}
}
}
// Ishlatish:
FormRow(label: "Name") {
TextField("Enter name", text: $name)
}
FormRow(label: "Gender") {
Picker("Select", selection: $gender) {
Text("Erkak").tag(Gender.male)
Text("Ayol").tag(Gender.female)
}
}
Muhim qoida: @ViewBuilder bilan shaxsiy funksiya some View qaytarishi kerak, aniq tur yoki View protokoli emas. Faqat opaque tur aniq implementatsiyani yashirish va kompozitsiya moslashuvchanligini saqlash imkonini beradi.
Unumdorlik: shaxsiy @ViewBuilder funksiyalari body-dagi to'g'ridan-to'g'ri kod bilan solishtirganda qo'shimcha yuk hosil qilmaydi. Kompilyator chaqiriqlarni inline qiladi va natijaviy kodni optimallashtiradi. Body-ni @ViewBuilder funksiyalariga bo'lish unumdorlikni yo'qotmasdan o'qiluvchanlikni yaxshilaydi.
Tez-tez so'raladigan savollar
@ViewBuilder — bir nechta ifodalar va shartli kod blokini yagona View turiga aylantiruvchi result builder annotatsiyasidir. SwiftUI deklarativ interfeysi ichida tanish Swift sintaksisidan (if/else, switch, ixtiyoriy ifodalar) foydalanish imkonini beradi.
Cheklov buildBlock implementatsiyasi bilan bog'liq — har bir arlik uchun (1 dan 10 gacha) metodning alohida overloadi mavjud. Swift variadic generics-ni qo'llab-quvvatlamaydi, shuning uchun overloadlar soni qat'iy. Buni yengish uchun Group, ForEach yoki pastki komponentlardan foydalaning.
Yo'q, View protokoli yashirin @ViewBuilder-ni body xususiyatiga qo'llaydi. Biroq, bir nechta View qaytaradigan foydalanuvchi xususiyatlari, metodlari va yopilish parametrlari uchun annotatsiyani aniq ko'rsatish kerak. Aks holda kompilyator bir nechta ifodalarni qayta ishlay olmaydi.
Ixtiyoriy ifodalar uchun buildIf metodi ishlatiladi, u ixtiyoriy View-ni qabul qiladi va qiymat mavjud bo'lsa uni qaytaradi. Agar qiymat nil bo'lsa — buildIf nil qaytaradi va element ko'rsatilmaydi. Bu body-da if let ishlatishga imkon beradi.
Ha, Swift 5.9 dan boshlab @ViewBuilder switch-ni buildExpression metodi orqali qo'llab-quvvatlaydi. Kompilyator har bir case shoxini tegishli buildEither chaqiruviga aylantiradi. Switch qo'llab-quvvatlashi ichki joylashgan if/else konstruktsiyalariga nisbatan kodni o'qishni osonlashtiradi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.