@ViewBuilder — SwiftUI-də View iyerarxiyasının deklarativ qurulması üçün nəzərdə tutulmuş result builder annotasiyasıdır. Apple Developer Documentation, 2024-ə əsasən, @ViewBuilder çoxsaylı ifadələr və şərti məntiqi olan kod blokunu Swift kompilyatoru üçün anlaşılan vahid View tipinə çevirir. Bu annotasiya olmadan SwiftUI-nin if/else və body-də çoxsaylı elementləri olan tanış deklarativ sintaksisindən istifadə etmək mümkün olmazdı.
Əsas məqamlar
@ViewBuilder — result builder (SE-0289) nümunəsini həyata keçirən annotasiyadır və SwiftUI-yə deklarativ sintaksis vasitəsilə bir neçə View-i bir kompozisiyada toplamağa imkan verir. O, çoxsaylı ifadələri, şərti konstruksiyaları və opsional dəyərləri müvafiq tiplərə avtomatik bükür: TupleView, ConditionalContent, OptionalContent.
Result builder meydana çıxmazdan əvvəl proqramçılar elementləri əl ilə VStack və ya HStack-ə bükməli, şərti məntiq üçün üçlü operatorlar və ya fabrik metodlarından istifadə etməli idilər. @ViewBuilder SwiftUI sintaksisini yığcam və oxunaqlı etdi, if/else və dövrləri olan adi Swift kimi görünən kod yazmağa imkan verdi.
Swift Evolution SE-0289-a əsasən, result builders SwiftUI-yə bağlı olmayan ümumi mexanizmdir. @ViewBuilder bu mexanizmin implementasiyalarından biridir, sətirlər qurmaq üçün @StringBuilder və digər DSL-lər üçün kitabxana implementasiyaları ilə yanaşı. SwiftUI-də @ViewBuilder təkcə body üçün deyil, həm də konteyner parametrləri-zamkaniyaları üçün istifadə olunur (VStack, HStack, ZStack, List).
İmperativ UIKit-də siz UIView yaradır, onun xassələrini konfiqurasiya edir və addSubview vasitəsilə iyerarxiyaya əlavə edirsiniz. @ViewBuilder ilə SwiftUI-də siz deklarativ şəkildə hansı View-lərin göstəriləcəyini təsvir edirsiniz və SwiftUI özü dövlət dəyişiklikləri əsasında elementlərin yaradılması, yenilənməsi və silinməsini idarə edir.
Result builder — ifadələr ardıcıllığını buildBlock, buildOptional, buildEither və digər statik metodlar vasitəsilə bir mürəkkəb dəyərə çevirən Swift mexanizmidir. Kompilyator @ViewBuilder annotasiyasını gördükdə, bu metodları avtomatik olaraq kod blokuna tətbiq edir.
@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-dən 10-dək ifadə qəbul edir və TupleView qaytarır. Hər arlıq (ifadə sayı) buildBlock-in öz overloaduna malikdir: buildBlock<C0>-dan buildBlock<C0, C1, ..., C9>-dək. Məhz buna görə bir @ViewBuilder blokunda elementlərin sayı 10 ilə məhdudlaşır.
buildEither (first/second) if/else konstruksiyalarını emal edir. Hər budaq müvafiq metoda ötürülür və nəticə ConditionalContent-ə bükülür — budaqların konkret tiplərini gizlədən və SwiftUI üçün vahid interfeys təmin edən tip.
SwiftUI-də body xassəsi artıq @ViewBuilder ilə qeyri-aşkar annotasiya olunub — siz bu annotasiyanı kodda görmürsünüz, amma kompilyator onu avtomatik tətbiq edir. Lakin bir neçə View qaytaran istifadəçi xassələri və ya zamkaniyə parametrləri üçün annotasiyanı aşkar şəkildə göstərmək lazımdır.
Məhdudiyyət 1 — blokda 10 element. Bu @ViewBuilder-in ən məşhur məhdudiyyətidir. Bir səviyyədə 10-dan çox element göstərmək lazımdırsa, kompilyator xəta verir. Bunu Group, ForEach, List və ya altkomponentlərə bölməklə keçmək olar. Group vizual iç-içəlik əlavə etmir, lakin hər Group bir element sayılır.
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")
}
}
}
Məhdudiyyət 2 — bəzi konstruksiyaların dəstəklənməməsi. @ViewBuilder do/catch, guard, for-in (ForEach olmadan) və digər idarəetmə konstruksiyalarını dəstəkləmir. Dövrlər üçün ForEach-dən identifikasiya edilə bilən məlumatlarla istifadə edin. Xəta emalı üçün Result və ya opsional dəyərlər qəbul edən ayrıca View-lərdən istifadə edin.
Məhdudiyyət 3 — debug çətinliyi. @ViewBuilder-də xətalarda kompilyator kök səbəbi tapmaq çətin olan uzun mesajlar verir. Tipik problemlər: if/else budaqlarında tip uyğunsuzluğu, 10 element limitinin aşılması və ya tələb olunan buildBlock overloadunun olmaması.
Nümunə 1: if/else ilə şərti göstərmə. @ViewBuilder-in ən çox yayılmış istifadə ssenarisi. Üçlü operatorlar və ya fabrik metodları olmadan vəziyyətdən asılı olaraq müxtəlif View-lər göstərməyə imkan verir.
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)
}
}
}
Nümunə 2: funksiya və init parametrlərində @ViewBuilder. Zamkaniyə vasitəsilə uşaq View-lər qəbul edən təkrar istifadə olunan konteynerlər yaratmaq üçün istifadə olunur. Bu kitabxana və UI komponentləri üçün standart nümunədir.
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)
}
}
Nümunə 3: ForEach ilə kompozisiya. @ViewBuilder ForEach ilə düzgün işləyərək məlumat massivindən elementlərin dinamik generasiyasını təmin edir. Hər ForEach elementi @ViewBuilder kontekstində bir ifadə sayılır.
Xüsusi ViewBuilder — @ViewBuilder ilə annotasiya olunmuş, some View qaytaran istifadəçi funksiyası və ya xassəsidir. Belə funksiyalar mürəkkəb göstərmə məntiqini kapsullaşdırmağa və onu tətbiqin müxtəlif hissələrində təkrar istifadə etməyə imkan verir.
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
}
}
}
// Istifadə:
FormRow(label: "Name") {
TextField("Enter name", text: $name)
}
FormRow(label: "Gender") {
Picker("Select", selection: $gender) {
Text("Kişi").tag(Gender.male)
Text("Qadın").tag(Gender.female)
}
}
Vacib qayda: @ViewBuilder ilə xüsusi funksiya some View qaytarmalıdır, konkret tip və ya View protokolu yox. Yalnız opaque tip konkret implementasiyanı gizlətməyə və kompozisiya elastikliyini qorumağa imkan verir.
Performans: xüsusi @ViewBuilder funksiyaları body-də birbaşa kodla müqayisədə əlavə yük yaratmır. Kompilyator çağırışları inline edir və nəticə kodu optimallaşdırır. Body-ni @ViewBuilder funksiyalarına bölmək performans itkisi olmadan oxunaqlılığı artırır.
Tez-tez verilən suallar
@ViewBuilder — çoxsaylı ifadələri və şərtləri olan kod blokunu vahid View tipinə çevirən result builder annotasiyasıdır. SwiftUI-nin deklarativ interfeysi daxilində tanış Swift sintaksisindən (if/else, switch, opsional ifadələr) istifadə etməyə imkan verir.
Məhdudiyyət buildBlock implementasiyası ilə bağlıdır — hər arlıq üçün (1-dən 10-dək) metodun ayrıca overloadu mövcuddur. Swift variadic generics-i dəstəkləmir, buna görə overloadların sayı sabitdir. Bunu keçmək üçün Group, ForEach və ya altkomponentlərdən istifadə edin.
Xeyr, View protokolu qeyri-aşkar @ViewBuilder-i body xassəsinə tətbiq edir. Lakin bir neçə View qaytaran istifadəçi xassələri, metodları və zamkaniyə parametrləri üçün annotasiyanı aşkar göstərmək lazımdır. Əks halda kompilyator çoxsaylı ifadələri emal edə bilməyəcək.
Opsional ifadələr üçün buildIf metodu istifadə olunur, o opsional View qəbul edir və dəyər varsa onu qaytarır. Dəyər nil-dirsə — buildIf nil qaytarır və element göstərilmir. Bu, body-də if let istifadəsinə imkan verir.
Bəli, Swift 5.9-dan etibarən @ViewBuilder switch-i buildExpression metodu vasitəsilə dəstəkləyir. Kompilyator hər case budağını müvafiq buildEither çağırışına çevirir. Switch dəstəyi iç-içə if/else konstruksiyaları ilə müqayisədə kodu daha oxunaqlı edir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun