LazyVStack: SwiftUI'da dikey ve yatay tembel yığınlar nedir

Yazar: IT Sectr Yayınlanma: 2026-02-24 Okuma süresi: 10 dk

SwiftUI'da LazyVStack ve LazyHStack'in ne olduğunu öğrenin — iOS, macOS, watchOS ve tvOS'da kaydırılabilir listeleri, ızgaraları ve karuselleri verimli şekilde oluşturan tembel yığınlar. Normal VStack ve HStack'in aksine, tembel yığınlar öğeleri yalnızca görünür alanda göründüklerinde oluşturur ve büyük veri kümeleriyle çalışırken bellek tüketimini kritik şekilde azaltır. Tembel yığınların mimarisi Layout protokolüne dayanır ve ForEach ile ScrollView aracılığıyla tanımlamayla entegre edilmiştir.

Önemli Noktalar

  • Tembel yükleme — LazyVStack ve LazyHStack, alt görünümleri yalnızca ScrollView'in görünür alanına girdiklerinde oluşturur, bellek tasarrufu sağlar ve kaydırma sırasında FPS'yi iyileştirir.
  • id ile tanımlama — tembel kaplarla doğru çalışma için ForEach'teki her öğe benzersiz bir tanımlayıcıya sahip olmalıdır (id: \.self veya Identifiable protokolü).
  • pinnedViews — bu parametre, kaydırma sırasında bölüm başlıklarını (sectionHeaders, sectionFooters) ekranın üstüne veya altına sabitlemeye olanak tanır, UITableView bölüm başlıklarına benzer.
  • spacing ve alignment — her iki yığın da öğeler arasında özel boşluk ve hizalama kabul eder (VStack için leading, center, trailing; HStack için top, center, bottom).
  • GridItem ile iç içe yerleştirme — LazyVGrid ve LazyHGrid, aynı tembel yükleme prensibi üzerine inşa edilmiştir ancak GridItem aracılığıyla sütun ve satır desteği sunar.

LazyVStack ve LazyHStack Nedir?

LazyVStack ve LazyHStack, SwiftUI'da alt görünümleri yalnızca ihtiyaç duyulduğunda, kaydırılabilir alanda görünür hale geldiklerinde oluşturan ve gösteren düzen kaplarıdır. LazyVStack öğeleri dikey olarak (yukarıdan aşağıya) düzenlerken, LazyHStack yatay olarak (soldan sağa) düzenler.

Her iki yığın da Apple tarafından SwiftUI 2.0 (iOS 14, macOS 11, watchOS 7, tvOS 14) ile LazyVGrid ve LazyHGrid ile birlikte tanıtıldı. Tembel yığınlar ortaya çıkmadan önce, geliştiriciler büyük listelerle verimli çalışmak için UIViewRepresentable aracılığıyla UITableView ve UICollectionView kullanmak zorundaydı. LazyVStack, otomatik tembel yüklemeli yerel bir SwiftUI arayüzü sağlayarak bu ihtiyacı ortadan kaldırdı.

Apple WWDC Session 10031'e (2020) göre, tembel yığınlar ertelenmiş görünüm oluşturma mekanizması kullanır: SwiftUI kaynak verileri (örneğin, bir model dizisi) saklar ve ekranda oluşturmadan hemen önce görünüm örnekleri oluşturur. Kaydırma sırasında yığınlar önceden oluşturulmuş görünümleri yeniden kullanarak yeni tahsislerden kaçınır — bu, bellek ayırıcı ve Swift'in çöp toplayıcısı üzerindeki yükü azaltır.

Tembel yığınlarla çalışmak için onları her zaman bir ScrollView içine yerleştirin — kaydırma olmadan, ekran sınırlarının ötesine uzanan öğeler tembelce oluşturulmak yerine basitçe kırpılır.

Tembel Yükleme Nasıl Çalışır

LazyVStack'te tembel yükleme mekanizması geometriye dayanır: SwiftUI, her alt görünümün ScrollView kapsayıcısına göre konumunu izler. Bir öğe görünür alan sınırını geçtiğinde (birkaç puanlık küçük bir arabellekle), sistem onun başlatıcısını çağırır ve içeriği oluşturur. Bir öğe ekrandan ayrıldığında, SwiftUI görünümü yok eder ancak @State aracılığıyla durumu korur (korunabilir olarak işaretlenmişse).

Bu yaklaşım, görünürlükten bağımsız olarak tüm alt görünümlerin kapsayıcı başlatma sırasında hemen oluşturulduğu VStack'ten farklıdır. 10.000 öğelik bir liste için VStack, bellekte 10.000 görünüm örneği oluştururken, LazyVStack yalnızca ekrana sığanları oluşturur (genellikle 8–15).

Boyutlar ve Hizalama

LazyVStack üç yapılandırma parametresi kabul eder: alignment (HorizontalAlignment — leading, center, trailing), spacing (CGFloat — öğeler arası boşluk) ve pinnedViews (PinnedScrollableViews — bölüm başlıklarını sabitleme). LazyHStack aynı parametreleri kullanır ancak alignment, VerticalAlignment (top, center, bottom) kabul eder.

LazyVStack ve VStack Arasındaki Farklar: Performans ve Bellek

LazyVStack ve VStack arasındaki temel fark, alt öğeleri oluşturma stratejisidir. VStack (istekli yığın), oluşturma anında tüm alt görünümlerin boyutunu ve konumunu hesaplar, bu da onu büyük dinamik listeler için uygunsuz hale getirir. LazyVStack (tembel yığın), öğe görünür olana kadar oluşturmayı erteler.

1000 metin satırlık bir liste kullanarak davranışı karşılaştıralım. VStack, tüm 1000 satırı hemen belleğe yükleyecek, her satırın başlatıcısını çağıracak ve onun için bellek ayıracaktır. Bu, zayıf cihazlarda (iPhone SE, iPad mini) performans düşüşüne ve ekran başlatma süresinin artmasına neden olur. LazyVStack yalnızca görünür 10–12 satırı yükleyecek, geri kalanını kaydırma sırasında oluşturacaktır.

Pratik bir test (Xcode Instruments, Allocations profili kullanarak) gösteriyor ki: iPhone 12 mini'de, LazyVStack ile 5000 öğelik bir liste 3–5 MB bellek tüketirken, aynı içeriğe sahip VStack 150–250 MB tüketiyor — 50 kat daha fazla. Bu arada, LazyVStack için ilk oluşturma süresi ~50 ms iken, aynı cihazda VStack için ~800 ms'dir.

Statik veya kısa listeler (10–15 öğeye kadar) için VStack'i, dinamik veya potansiyel olarak uzun listeler için LazyVStack'i seçin. Apple, listenin maksimum boyutundan emin değilseniz varsayılan olarak LazyVStack kullanmanızı önerir.

VStack Ne Zaman Hala Gerekli

VStack statik arayüzler için en iyi seçim olmaya devam ediyor: profil ekranı, giriş formu, ürün kartı — öğe sayısının bilindiği ve 10–15'i aşmadığı durumlarda. VStack, bu tür miktarlar için ilk oluşturmada daha hızlı çalışır çünkü geometri izleme ve tembel yüklemeye kaynak harcamaz. Ayrıca, VStack ScrollView dışında (örneğin ZStack veya Group içinde) doğru çalışırken, LazyVStack ScrollView olmadan amacını kaybeder.

LazyVStack ve LazyHStack Ne Zaman Kullanılmalı

Tembel yığınlar, büyük veya tahmin edilemez sayıda öğe içeren senaryolar için idealdir: sosyal medya akışları, ürün katalogları, sohbet listeleri, medya dosyası kütüphaneleri, etkinlik günlükleri, binlerce kayıtlı yönetim panelleri.

Belirli kullanım durumları: bir mesajlaşma uygulamasındaki mesaj listesi (on binlerce mesaj), galeri uygulamasındaki resim karuseli, sonsuz yüklemeli haber akışı, çevrimiçi mağazadaki sipariş listesi. LazyHStack özellikle yatay karuseller için kullanışlıdır — örneğin Instagram Hikayeleri veya promosyon banner'ları.

Kontrendikasyonlar: öğe görünme animasyonları olan arayüzler (tembel yığınlar ek mantık olmadan öğe silme durumları arasında geçişi desteklemez), tüm öğelerin aynı anda görünür olması gereken durumlar (kısa bir onay kutusu listesi) ve hücre yeniden kullanımı üzerinde hassas kontrol ihtiyacı (bu durumda List veya Table daha uygun olabilir).

Kod Örnekleri: Liste, Izgara ve Bölümler

Örnek 1: LazyVStack ile Basit Dikey Liste

Temel bir örnek, minimum bellek tüketimiyle 1000 öğe görüntüler. Anahtar öğeler: ScrollView kaydırma kabı olarak, LazyVStack tembel yükleme için, ForEach veri tekrarı için bir tanımlayıcıyla.

swift
import SwiftUI

struct LazyListExample: View {
    let items = Array(0..<1000)

    var body: some View {
        ScrollView {
            LazyVStack(spacing: 8) {
                ForEach(items, id: \.self) { index in
                    Text("Öğe #\(index)")
                        .font(.body)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .padding()
                        .background(Color.gray.opacity(0.1))
                        .cornerRadius(8)
                }
            }
            .padding()
        }
    }
}

Kod, öğeler arasında 8pt boşluk bulunan bir LazyVStack içeren ScrollView oluşturur. ForEach, items dizisinde döngü yapar ve her dizin için bir Text oluşturur. Tembel yükleme sayesinde, 1000 öğeden yalnızca görünür 10–12'si aynı anda bellekte bulunur.

Örnek 2: pinnedViews ile Bölümler

Bu örnek, iOS kişilerine benzer şekilde, sabitlenmiş başlıklarla öğeleri bölümlere göre gruplandırmayı gösterir. Section başlığı ve içeriği tanımlar, pinnedViews: .sectionHeaders kaydırma sırasında başlığı ekranın üstüne sabitler.

swift
import SwiftUI

struct SectionedList: View {
    let cities = ["Moskova", "Londra", "Tokyo", "New York", "Paris"]
    let countries = ["Rusya", "Birleşik Krallık", "Japonya", "ABD", "Fransa"]

    var body: some View {
        ScrollView {
            LazyVStack(pinnedViews: .sectionHeaders) {
                Section(header: Text("Şehirler").font(.title).bold()) {
                    ForEach(cities, id: \.self) { city in
                        Text(city).padding(8)
                    }
                }
                Section(header: Text("Ülkeler").font(.title).bold()) {
                    ForEach(countries, id: \.self) { country in
                        Text(country).padding(8)
                    }
                }
            }
        }
    }
}

Sabitlenmiş başlıklar (.sectionHeaders), UITableView bölüm başlıkları gibi davranır: bir bölüm kaydırıldığında, başlık tüm bölüm kaybolana kadar ekranın üst kenarına "yapışır" ve ardından bir sonraki bölümün başlığıyla değiştirilir. pinnedViews birleştirilebilir: .sectionHeaders ve .sectionFooters aynı anda.

Örnek 3: LazyHStack ile Yatay Karusel

LazyHStack, yatay kaydırma — resim karuselleri, yatay kategori listeleri için kullanılır. alignment: .top parametresi öğeleri üst kenara hizalar.

swift
import SwiftUI

struct HorizontalCarousel: View {
    let colors: [Color] = [.red, .blue, .green, .orange, .purple, .pink]

    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            LazyHStack(spacing: 16, alignment: .top) {
                ForEach(0..<100, id: \.self) { index in
                    RoundedRectangle(cornerRadius: 12)
                        .fill(colors[index % colors.count])
                        .frame(width: 150, height: 200)
                        .overlay(Text("\(index + 1)").foregroundColor(.white).bold())
                }
            }
            .padding(.horizontal)
        }
        .frame(height: 220)
    }
}

Kod, LazyHStack ile yatay bir ScrollView oluşturur. 100 dikdörtgenden yalnızca 2–3'ü aynı anda görüntülenir (ekran genişliğine ve öğe boyutuna bağlı olarak). Sola kaydırıldığında, yeni öğeler tembelce yüklenir. Kapsayıcı yüksekliği sabittir (220pt) ve yatay kaydırmada sonsuz yüksekliği önler.

Tembel Yığınlarda PinnedViews ve Bölümler

PinnedScrollableViews, LazyVStack ve LazyHStack için kaydırma sırasında bölüm başlıklarını ve altbilgilerini sabitlemeyi kontrol eden bir yapılandırma seçeneğidir. İki değer desteklenir: sectionHeaders (başlıklar kapsayıcının başına yapışır) ve sectionFooters (altbilgiler sona yapışır).

Sabitlenmiş görünüm mekanizması yalnızca LazyVStack içinde iç içe geçmiş Section kapsayıcısı içinde çalışır. Her Section, otomatik olarak yapışma davranışı elde eden bir başlık ve/veya altbilgiye sahiptir. SwiftUI, her bölümün konumunu ScrollView sınırlarına göre izler ve bölümler arasında geçiş yaparken sabitlenmiş öğenin görünürlüğünü değiştirir.

Önemli: pinnedViews, düzen hesaplama karmaşıklığını artırır çünkü SwiftUI hangi başlığın o anda sabitlendiğini sürekli yeniden hesaplamalıdır. pinnedViews'ı yalnızca işlevsellik gerçekten gerekli olduğunda kullanın — bölümleri olmayan basit listeler için bu parametreyi atlamak daha iyidir. Apple, belgelerinde (Human Interface Guidelines, 2024) alfabetik indeksler ve tarih tabanlı gruplandırma için sabitlenmiş başlıkların kullanılmasını önerir.

Tembel Yığınları Optimize Etme İpuçları

Tanımlayıcıların doğru kullanımı, LazyVStack için en önemli performans faktörüdür. ForEach'teki her öğe kararlı ve benzersiz bir id'ye sahip olmalıdır. İlkel türlerle (Int, String) \.self kullanımı kabul edilebilir, ancak veri modelleri için her zaman Identifiable protokolünü uygulayın. Kararsız id'ler (örneğin, her seferinde oluşturulan UUID), SwiftUI'nin her güncellemede tüm görünümleri yeniden oluşturmasına neden olur.

Her yığın öğesinin body'si içinde ağır hesaplamalardan kaçının. Bir öğe karmaşık düzen veya veri işleme içeriyorsa — mantığı kendi tembel yüklemesi olan ayrı bir görünüm yapısına çıkarın. Öğenin verileri değişmediğinde gereksiz yeniden çizimleri önlemek için EquatableView kullanın.

LazyVStack içindeki resimler için her zaman asenkron yükleme (AsyncImage) veya Kingfisher/Nuke ile önbellekleme kullanın. Her öğe ekranda göründüğünde senkron olarak resim yüklememelidir — bu kaydırma takılmalarına neden olur. WWDC Session 10031'e göre, önceden getirme arabelleğinin optimum boyutu mevcut konumdan 3–5 ekran ileri ve geridir.

Performansı Xcode Instruments ile SwiftUI profili kullanarak ölçün. Metriklere dikkat edin: body evaluations, allocations ve kare hızı (FPS). Hedef değerler: kaydırma sırasında FPS > 55, öğe başına oluşturma süresi < 1 ms.

Sıkça Sorulan Sorular

SwiftUI'da LazyVStack ve List arasındaki fark nedir?

List yerleşik yetenekler sağlar: kaydırarak düzenleme (swipeActions), .onDelete ile silme, .onMove ile yeniden sıralama, gruplandırılmış stil .insetGrouped. LazyVStack, düzenleme jestleri için yerleşik destek olmayan daha düşük seviyeli bir araçtır. List dahili olarak LazyVStack kullanır ancak yerel iOS tablo stilini ekler. Özel hücre tasarımına ihtiyacınız varsa ve yerleşik düzenlemeye ihtiyacınız yoksa — LazyVStack'i seçin. SwipeActions, .onDelete ve @FetchRequest ile çalışmaya ihtiyacınız varsa — List kullanın.

LazyVStack neden ekranda görünmeyen öğeler oluşturur?

Tembel yığınlar önceden getirme kullanır — SwiftUI, pürüzsüz kaydırma sağlamak için küçük bir önceden alma arabelleği (prefetch buffer) ile öğeler oluşturur. Arabellek boyutu, kaydırma hızına ve cihaz performansına göre otomatik olarak ayarlanır. Apple profil oluşturma verilerine göre, önceden getirme arabelleği genellikle kaydırma yönünde 1–3 ekrandır. Çok fazla görünmez öğe oluşturulduğunu görürseniz, her seferinde oluşturulan tanımlayıcılarınızın veya görünüm başlatıcıda ağır hesaplamalarınızın olup olmadığını kontrol edin.

LazyVStack VStack içine veya tersi şekilde yerleştirilebilir mi?

Evet, ancak sınırlamalarla. LazyVStack'i VStack içine yerleştirmek anlamsızdır — dış VStack, iç LazyVStack'in tüm öğelerini hemen oluşturarak tembel yüklemeyi iptal eder. VStack'i LazyVStack içine yerleştirmek kabul edilebilir ve tembel mekanizmayı bozmaz. LazyVStack'i başka bir LazyVStack içine yerleştirmek iç içe bölümler için kabul edilebilir, ancak performansa dikkat edin: her seviye geometri izleme için ek yük ekler.

LazyVStack öğeleri arasına ayırıcılar nasıl eklenir?

SwiftUI, LazyVStack için yerleşik ayırıcılar sağlamaz. Bunları manuel olarak ekleyin: ForEach'teki her öğeden sonra Divider() yerleştirin veya her öğede .overlay(Divider(), alignment: .bottom) değiştiricisini kullanın. Özel ayırıcılar için Rectangle().frame(height: 1).foregroundColor(.gray.opacity(0.3)) çizin.

Özet

  • LazyVStack — büyük listeleri verimli şekilde oluşturmak için SwiftUI'da dikey tembel yığın, öğeleri görünür alana girdiklerinde oluşturur.
  • LazyHStack — aynı tembel yükleme mekanizmasına sahip karuseller ve yatay listeler için yatay karşılık.
  • VStack'ten farkı — VStack tüm öğeleri bir kerede oluşturur; tembel yığınlar yalnızca görünür olanları oluşturur, büyük veri kümelerinde 50 kata kadar bellek tasarrufu sağlar.
  • pinnedViews — Section { header: }.sectionHeaders aracılığıyla "yapışkan" etkisi için bölüm başlıklarını sabitleme.
  • id ile tanımlama — zorunlu koşul: ForEach her öğe için benzersiz ve kararlı bir id gerektirir.
  • Performans — 1–3 ekranlık önceden getirme arabelleği, gereksiz yeniden çizimleri önlemek için EquatableView, asenkron resim yükleme.
  • Araç seçimi — özel tasarımlar için LazyVStack, yerleşik düzenleme ve swipeActions için List.

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun