SwiftUI ile uzun listelerin performansını iyileştirme: pratik çözümler
Uzun SwiftUI listeleri için performans iyileştirmeleri: yeniden render'lar, kararlı satır kimliği, sayfalama, resim yükleme ve eski iPhone'larda akıcı kaydırma için pratik çözümler.

SwiftUI uygulamalarında “yavaş listeler” nasıl görünür
SwiftUI'de bir “yavaş liste” genellikle bir hata değildir. Parmak hareketinize UI'nin yetişemediği andır. Kaydırırken fark edersiniz: liste tereddüt eder, kareler düşer ve her şey ağır hissedilir.
Tipik işaretler:
- Özellikle eski cihazlarda kaydırma takılır
- Satırlar titrer veya kısa süreliğine yanlış içerik gösterir
- Dokunuşlar gecikir veya kaydırma işlemleri geç başlar
- Telefon ısınır ve pil beklenenden hızlı tükenir
- Kaydırdıkça bellek kullanımı büyür
Uzun listeler her satır “küçük” görünse bile yavaş hissedebilir, çünkü maliyet sadece pikselleri çizmek değildir. SwiftUI hâlâ her satırın ne olduğunu belirlemek, düzeni hesaplamak, yazı tiplerini ve resimleri çözmek, biçimlendirme kodunuzu çalıştırmak ve veri değiştiğinde güncellemeleri diff'lemek zorundadır. Bu işlerden herhangi biri çok sık oluyorsa, liste bir darboğaz haline gelir.
Ayrıca iki fikri ayırmak işe yarar. SwiftUI'de bir “yeniden render” genellikle bir görünümün body'sinin yeniden hesaplanması demektir. Bu kısım genelde ucuzdur. Pahalı olan, yeniden hesaplamanın tetiklediği iştir: ağır düzen, resim dekodlama, metin ölçümü veya SwiftUI'nin kimliğinin değiştiğini düşünmesi nedeniyle birçok satırın yeniden oluşturulması.
2.000 mesajlık bir sohbet hayal edin. Yeni mesajlar her saniye geliyor ve her satır zaman damgalarını biçimlendiriyor, çok satırlı metni ölçüyor ve avatarları yüklüyor. Sadece bir öğe ekleseniz bile kötü kapsamlanmış bir durum değişikliği birçok satırın yeniden değerlendirilmesine ve bazı satırların yeniden çizilmesine neden olabilir.
Amaç mikro-optimizasyon değil. Hedef akıcı kaydırma, anında dokunuş ve yalnızca gerçekten değişen satırları etkileyen güncellemeler. Aşağıdaki düzeltmeler kararlı kimlik, daha ucuz satırlar, gereksiz güncellemelerin azaltılması ve kontrollü yükleme üzerine odaklanır.
Temel nedenler: kimlik, satır başına iş ve güncelleme fırtınaları
Bir SwiftUI listesi yavaş hissettiğinde, nadiren sebep “çok fazla satır”dır. Kaydırma sırasında fazladan iş olur: satırların yeniden inşası, düzenin yeniden hesaplanması veya resimlerin defalarca yeniden yüklenmesi.
Çoğu temel neden üç gruba ayrılır:
- Kararsız kimlik: satırların tutarlı bir
id'si yok ya da değişebilen değerler için\.selfkullanıyorsunuz. SwiftUI eski satırları yeni satırlarla eşleyemez, bu yüzden gereğinden fazla yeniden oluşturma olur. - Satır başına çok fazla iş: tarih biçimlendirme, filtreleme, resim yeniden boyutlandırma veya satır görünümünde ağ/diske dayalı işler yapmak.
- Güncelleme fırtınaları: yazma, bir zamanlayıcı darbeleri veya ilerleme güncellemeleri gibi tek bir değişiklik sık sık durum güncellemeleri tetikler ve liste tekrar tekrar yenilenir.
Örnek: 2.000 siparişiniz var. Her satır para birimini biçimlendiriyor, atfedilmiş bir metin oluşturuyor ve bir resim fetch başlatıyor. Bu arada üst görünümdeki "son senkron" zamanı her saniye güncelleniyor. Sipariş verisi değişmese bile o zamanlayıcı listeyi yeterince sık geçersiz kılabilir ve kaydırma takılmasına neden olur.
List ve LazyVStack neden farklı hissedebilir
List bir scroll view'den daha fazlasıdır. Tablo/collection davranışı ve sistem optimizasyonları etrafında tasarlanmıştır. Genelde büyük veri kümeleriyle daha az bellek kullanarak iyi çalışır, ama kimlik ve sık güncellemeler konusunda hassas olabilir.
ScrollView + LazyVStack düzen ve görsellik üzerinde daha fazla kontrol verir, ama yanlışlıkla ekstra düzen işi yapmak veya pahalı güncellemeler tetiklemek daha kolaydır. Eski cihazlarda bu ekstra iş daha erken ortaya çıkar.
UI'inizi yeniden yazmadan önce ölçün. Kararlı ID'ler, satır dışına taşınmış işler ve durum çalkantısını azaltmak gibi küçük düzeltmeler genelde konteyner değiştirmeden sorunu çözer.
SwiftUI'nin verimli diff yapabilmesi için satır kimliğini düzeltin
Uzun bir liste takılma hissediyorsa, sebeplerin başında kimlik gelir. SwiftUI hangi satırların yeniden kullanılabileceğini ID karşılaştırarak belirler. Bu ID'ler değişirse, SwiftUI satırları yeni kabul eder, eskilerini atar ve gereğinden fazla yeniden oluşturma yapar. Bu, rastgele yeniden render'lar, kaydırma pozisyonunun kaybolması veya gereksiz animasyonlar gibi davranabilir.
En basit kazanım: her satırın id'sini veri kaynağınızla bağlantılı ve sabit yapın.
Yaygın bir hata, kimliği görünüm içinde üretmektir:
ForEach(items) { item in
Row(item: item)
.id(UUID())
}
Bu her render'da yeni bir ID üretir, böylece her satır her seferinde “farklı” olur.
Modelinizde zaten var olan ID'leri tercih edin; örneğin veritabanı birincil anahtarı, sunucu ID'si veya kararlı bir slug. Yoksa, görünüm içinde değil, model oluşturulduğunda bir tane oluşturun ve saklayın.
struct Item: Identifiable {
let id: Int
let title: String
}
List(items) { item in
Row(item: item)
}
İndekslere dikkat edin. ForEach(items.indices, id: \\.self) kimliği pozisyona bağlar. Eğer ekleme, silme veya sıralama olursa, satırlar “taşınır” ve SwiftUI yanlış görünümü yeniden kullanabilir. Dizi hiç yeniden sıralanmıyorsa indeksleri kullanın.
id: \.self kullanıyorsanız, elemanın Hashable değeri zaman içinde sabit olsun. Hash, bir alan güncellendiğinde değişiyorsa, satırın kimliği de değişir. Equatable ve Hashable için güvenli kural: bunları tek, sabit bir ID'ye dayanacak şekilde oluşturun; düzenlenebilir özelliklere (ör. name, isSelected) dayandırmayın.
Kontrol listesi:
- ID'ler veri kaynağından geliyor (görünüm içinde
UUID()değil) - Satır içeriği değiştiğinde ID değişmiyor
- Kimlik, liste asla yeniden sıralanmıyorsa dışındaki durumlarda dizi pozisyonuna bağlı değil
Yeniden render'ları azaltmak için satır görünümünü daha ucuz yapın
Uzun bir liste genelde her satır body'sinde çok fazla iş yapıldığı için yavaş hisseder. Hedef basit: her satır yeniden oluşturulduğunda ucuz olsun.
Gizli maliyetlerden biri, çok büyük değerleri satıra geçirmek olabilir. Büyük struct'lar, derin modeller veya ağır hesaplanan özellikler UI değişmese bile ekstra işe neden olabilir. Diziler, string'ler, tarih/numara biçimlendirme, resim yeniden boyutlandırma veya karmaşık layout ağaçları daha sık yeniden oluşturuluyor olabilir.
Ağır işleri body dışına taşıyın
Eğer bir şey yavaşsa, satır body'sinde defalarca yeniden oluşturmayın. Veri geldiğinde önceden hesaplayın, view model'de önbelleğe alın veya küçük bir yardımcı ile memoize edin.
Satır düzeyinde hız maliyeti getiren işler:
- Her satırda yeni bir
DateFormatterveyaNumberFormatteroluşturmak bodyiçinde ağır string biçimlendirmeleri (join, regex, markdown parsing)bodyiçinde.mapveya.filterile türetilmiş diziler üretmek- Görünüm içinde büyük blob'ları okuyup dönüştürmek (ör. JSON decode)
- Çok fazla iç içe stack ve koşul içeren aşırı karmaşık layout
Basit bir örnek: formatlayıcıları statik tutun ve satıra önceden biçimlendirilmiş string'ler gönderin.
enum Formatters {
static let shortDate: DateFormatter = {
let f = DateFormatter()
f.dateStyle = .medium
f.timeStyle = .none
return f
}()
}
struct OrderRow: View {
let title: String
let dateText: String
var body: some View {
HStack {
Text(title)
Spacer()
Text(dateText).foregroundStyle(.secondary)
}
}
}
Satırları bölün ve Equatable kullanın (uygun olduğunda)
Eğer yalnızca küçük bir parça değişiyorsa (ör. bir rozet sayısı), onu alt görünüme izole edin ki satırın geri kalanı stabil kalsın. Değer odaklı UI için bir alt görünümü Equatable yapmak (veya EquatableView ile sarmak), girdiler değişmediğinde SwiftUI'nin işi atlamasına yardımcı olabilir. Equatable girdileri küçük ve spesifik tutun — tüm modeli değil.
Tam liste yenilenmelerini tetikleyen durum güncellemelerini kontrol edin
Bazen satırlar iyidir ama bir şey SwiftUI'ye tüm listeyi yenilemesini söylüyor. Kaydırma sırasında bile küçük ekstra güncellemeler takılmalara yol açabilir, özellikle eski cihazlarda.
Yaygın bir neden modeli çok sık yeniden oluşturmaktır. Bir üst görünüm yeniden oluşturuluyorsa ve siz görünümün sahip olduğu bir view modele @ObservedObject olarak bağlıysanız, SwiftUI onu yeniden oluşturabilir, abonlukları sıfırlayabilir ve yeni yayınlar tetikleyebilir. Görünüm modelin sahibi ise @StateObject kullanın, böylece bir kere oluşturulur ve stabil kalır. Dışarıdan enjekte edilen nesneler için @ObservedObject kullanın.
Sessiz bir performans katili de çok sık yayın yapmaktır. Zamanlayıcılar, Combine boru hatları ve ilerleme güncellemeleri saniyede birçok kez ateşleyebilir. Eğer yayımlanan bir özellik listeyi etkiliyorsa (veya ekranda kullanılan ortak bir ObservableObject üzerindeyse), her tik listeyi geçersiz kılabilir.
Örnek: Her tuş vuruşunda query'yi güncelleyen bir arama alanınız var ve 5.000 öğeyi filtreliyorsanız, hemen filtrelerseniz kullanıcı yazarken liste sürekli yeniden difflenir. Sorguyu debounce edin ve filtrelenmiş diziyi kısa bir duraklama sonrası güncelleyin.
Yardımcı desenler:
- Hızla değişen değerleri listeyi yöneten nesnenin dışında tutun (daha küçük nesneler veya lokal
@Statekullanın) - Arama ve filtrelemeyi debounce edin, böylece liste yazma durakladıktan sonra güncellenir
- Yüksek frekanslı zamanlayıcı yayınlarından kaçının; daha az sıklıkta güncelleyin veya yalnızca değer gerçekten değiştiğinde güncelleyin
- Satır başına durumları lokal tutun (
@State), global ve sık değişen bir değere bağlamayın - Büyük modelleri bölün: bir
ObservableObjectliste verileri için, diğeri ekran düzeyi UI durumu için olsun
Fikir basit: kaydırma zamanı sessiz olsun. Önemli bir şey değişmediyse, liste iş yapmak zorunda kalmamalı.
Doğru konteyneri seçin: List vs LazyVStack
Seçtiğiniz konteyner iOS'un sizin için ne kadar iş yaptığına etki eder.
List genelde klasik tablo görünümü için en güvenli seçimdir: metin, resimler, kaydırma işlemleri, seçim, ayırıcılar, düzenleme modu ve erişilebilirlik. Altında yıllardır Apple'ın geliştirdiği optimizasyonlardan faydalanır.
ScrollView + LazyVStack kartlar, karışık içerik blokları veya feed tarzı tasarım gibi özel düzenler için iyidir. “Lazy” olmasına rağmen, her durumda List ile aynı davranışı vermez. Çok büyük veri kümelerinde bu daha çok bellek kullanımı ve eski cihazlarda takılma anlamına gelebilir.
Basit bir karar kuralı:
- Klasik tablo ekranları (ayarlar, gelen kutusu, siparişler) için
Listkullanın - Özel düzenler ve karışık içerik için
ScrollView+LazyVStackkullanın - Binlerce öğeniz varsa ve sadece tabloya ihtiyacınız varsa, önce
Listile başlayın - Piksel hassas kontrol istiyorsanız
LazyVStackdeneyin, sonra bellek ve kare düşüşlerini ölçün
Ayrıca kaydırmayı yavaşlatan stil unsurlarına dikkat edin. Satır başına gölge, blur ve karmaşık overlay'ler ekstra render işine zorlayabilir. Derinlik istiyorsanız ağır efektleri tüm satır yerine küçük bir öğede (ikon gibi) uygulayın.
Somut örnek: 5.000 satırlık bir “Siparişler” ekranı List içinde genelde akıcı kalır çünkü satırlar yeniden kullanılır. Eğer LazyVStack'e geçip kart tarzı satırlar, büyük gölgeler ve birçok overlay ile inşa ederseniz, kod temiz görünse bile takılma görebilirsiniz.
Hafıza sıçramalarını önleyen ve akıcı hissettiren sayfalama
Sayfalama uzun listeleri hızlı tutar çünkü daha az satır render edilir, daha az model bellekte tutulur ve SwiftUI'ye daha az diff işi düşer.
Net bir sayfalama sözleşmesiyle başlayın: sabit bir sayfa boyutu (ör. 30–60 öğe), “daha fazla sonuç yok” bayrağı ve sadece fetch sırasında görünen bir yükleme satırı.
Yaygın tuzak, sonraki sayfayı yalnızca son satır göründüğünde tetiklemektir. Bu genelde çok geçtir ve kullanıcı sona geldiğinde bir duraklama görür. Bunun yerine son birkaç satırdan biri göründüğünde yüklemeye başlayın.
Basit bir örnek desen:
@State private var items: [Item] = []
@State private var isLoading = false
@State private var reachedEnd = false
func loadNextPageIfNeeded(currentIndex: Int) {
guard !isLoading, !reachedEnd else { return }
let threshold = max(items.count - 5, 0)
guard currentIndex >= threshold else { return }
isLoading = true
Task {
let page = try await api.fetchPage(after: items.last?.id)
await MainActor.run {
let newUnique = page.filter { p in !items.contains(where: { $0.id == p.id }) }
items.append(contentsOf: newUnique)
reachedEnd = page.isEmpty
isLoading = false
}
}
}
Bu yaklaşım, yinelenen satırlar (API sonuçlarının örtüşmesi), birden fazla onAppear çağrısından kaynaklanan yarış durumları ve aşırı yüklemeyi önler.
Liste çekme yenilemesini destekliyorsanız, sayfalama durumunu dikkatle sıfırlayın (öğeleri temizleyin, reachedEnd'i sıfırlayın, mümkünse devam eden görevleri iptal edin). Backend'i kontrol edebiliyorsanız, kararlı ID'ler ve cursor-temelli sayfalama UI'yi belirgin şekilde daha akıcı yapar.
Resimler, metin ve düzen: satır render'ını hafif tutun
Uzun listelerin yavaş hissetmesinin nedeni genelde konteyner değil satırdır. Resimler en sık suçludur: dekodlama, yeniden boyutlandırma ve çizim kaydırma hızınızı aşabilir, özellikle eski cihazlarda.
Uzak resimler yüklüyorsanız, ağır işler kaydırma sırasında ana iş parçacığında gerçekleşmemeli. Ayrıca 44–80 pt mini görünüm için tam çözünürlük varlıkları indirmekten kaçının.
Örnek: avatarlar içeren bir “Mesajlar” ekranı düşünün. Her satır 2000x2000 bir görsel indirip küçültüyor ve blur veya gölge uyguluyorsa, liste takılacaktır.
Resim işini öngörülebilir tutun
Yüksek etki yaratan alışkanlıklar:
- Sunucu tarafında veya önceden üretilmiş, gösterilen boyuta yakın küçük resimler kullanın
- Dekodlama ve yeniden boyutlandırmayı ana iş parçacığından uzak yapmaya çalışın
- Mini resimleri önbelleğe alın, böylece hızlı kaydırma yeniden çekme veya yeniden dekodlama yapmaz
- Flicker ve düzen sıçramalarını önlemek için nihai boyuta uyan bir yer tutucu kullanın
- Satırlardaki resimlerde ağır modifier'lardan (ağır gölgeler, maskeler, blur) kaçının
Düzeni stabil tutarak thrash'i önleyin
Satır yüksekliği sürekli değişiyorsa SwiftUI ölçüm yapmaya daha fazla zaman harcar. Satırları tahmin edilebilir tutmaya çalışın: küçük resimler için sabit frame'ler, tutarlı satır sınırları ve stabil boşluklar. Metin genişleyebiliyorsa; (ör. 1–2 satır) sınır koyun ki tek bir güncelleme ekstra ölçüm işine neden olmasın.
Yer tutucular da önemlidir. Daha sonra bir avatara dönüşecek gri bir daire aynı çerçeveyi işgal etmelidir, böylece satır kaydırma sırasında yeniden akmaz.
Ölçüm nasıl yapılır: gerçek darboğazları ortaya çıkaran Instruments kontrolleri
Sadece “takılıyor” diye hissetmekle performans işi kestirme olmaz. Instruments size ana iş parçacığında neyin çalıştığını, hızlı kaydırma sırasında neyin tahsis edildiğini ve hangi işlemlerin kare düşürmeye neden olduğunu gösterir.
Gerçek bir cihazda (destekliyorsanız daha eski bir cihazda) bir temel belirleyin. Tekrarlanabilir bir eylem yapın: ekranı açın, baştan sona hızlı kaydırın, bir kere daha yükle-yükle tetikleyin, sonra yukarı kaydırın. En kötü takılma noktalarını, bellek zirvesini ve UI'nin tepki verip vermediğini not edin.
En yararlı üç Instruments görünümü
Bunları birlikte kullanın:
- Time Profiler: Kaydırırken ana iş parçacığındaki ani zirvelere bakın. Düzen hesaplaması, metin ölçümü, JSON parsing ve resim dekodlama burada genelde takılmayı açıklar.
- Allocations: Hızlı kaydırma sırasında geçici nesnelerdeki sıçramaları izleyin. Bu genelde tekrarlanan biçimlendirme, yeni attributed string'ler veya satır başına model yeniden oluşturmayı işaret eder.
- Core Animation: Düşen kareleri ve uzun frame sürelerini doğrulayın. Bu, darboğazın rendering mi yoksa veri işi mi olduğunu ayırt etmeye yardımcı olur.
Bir zirve bulduğunuzda, çağrı ağacına tıklayın ve sorun: bu ekran başına mı oluyor, yoksa kaydırmada her satır için mi? İkincisi akıcı kaydırmayı bozar.
Kaydırma ve sayfalama olayları için signpost ekleyin
Birçok uygulama kaydırma sırasında ekstra iş yapar (resim yükleri, sayfalama, filtreleme). Signpost'lar timeline üzerinde bu anları görmenize yardımcı olur.
import os
let log = OSLog(subsystem: "com.yourapp", category: "list")
os_signpost(.begin, log: log, name: "LoadMore")
// fetch next page
os_signpost(.end, log: log, name: "LoadMore")
Her değişiklikten sonra, adım adım tekrar test edin. FPS iyileşiyorsa ama Allocations kötüleşiyorsa, takılma için bellek baskısı ile takas yapmış olabilirsiniz. Temel notları saklayın ve yalnızca sayıları doğru yöne taşıyan değişiklikleri tutun.
Liste performansını sessizce öldüren yaygın hatalar
Bazı sorunlar açıktır (büyük resimler, devasa veri setleri). Diğerleri veri büyüdükçe veya eski cihazlarda kendini gösterir.
1) Kararsız satır ID'leri
Görünüm içinde ID oluşturmak (ör. id: \.self referans tipleri için veya UUID()'yı satır gövdesinde kullanmak) klasik bir hatadır. SwiftUI güncellemeleri diff'lemek için kimliği kullanır. ID değişirse, satır yeni sayılır, yeniden oluşturulur ve önbelleğe alınmış düzen atılabilir.
Modelden gelen kararlı bir ID kullanın (veritabanı birincil anahtarı, sunucu ID'si veya model oluşturulduğunda saklanan UUID). Yoksa bir tane ekleyin.
2) onAppear içinde ağır işler
Satırlar kaydırma sırasında girip çıktığı için onAppear beklenenden daha sık çalışır. Eğer her satır burada resim dekodlama, JSON parsing veya veritabanı sorgusu başlatıyorsa tekrarlayan zirveler oluşur.
Ağır işleri satırdan çıkarın. Veri yüklendiğinde önceden hesaplayın, sonuçları önbelleğe alın ve onAppear'ı yalnızca sayfalamayı tetiklemek gibi ucuz görevlerle sınırlayın.
3) Tüm listeyi bağlayan bağlar ile satır düzenlemeleri
Her satıra büyük bir diziye @Binding geçirirseniz, küçük bir düzenleme büyük bir değişiklik gibi görünebilir. Bu, birçok satırın yeniden değerlendirilmesine ve bazen tüm listenin yenilenmesine yol açabilir.
Satıra immutable değerler gönderin ve değişiklikleri hafif bir eylemle geri iletin (ör. "id için favoriyi değiştir"). Satıra ait olan durumları yalnızca gerçekten oraya aitse satır içinde tutun.
4) Kaydırma sırasında çok fazla animasyon
Animasyonlar listede pahalıdır çünkü ekstra düzen geçişlerine neden olabilir. animation(.default, value:)'ı yüksek seviyede (bütün liste üzerinde) kullanmak veya sık değişen her durumu animasyonla yapmak kaydırmayı yapışkan hale getirebilir.
Basit tutun:
- Animasyonları yalnızca değişen satırla sınırlayın
- Hızlı kaydırma sırasında animasyondan kaçının (özellikle seçim/vurgulama için)
- Sık değişen değerlerde implicit animasyonlardan kaçının
- Karmaşık birleşik efektler yerine basit geçişleri tercih edin
Gerçek bir örnek: Her satır onAppear'da ağ isteği başlatan, UUID() ile id üreten ve "okundu" durumunu animasyonla değiştiren bir sohbet listesi. Bu kombinasyon sürekli satır değişimine neden olur. Kimliği düzeltmek, işi önbelleğe almak ve animasyonları sınırlamak aynı UI'yi anında daha akıcı hale getirebilir.
Hızlı kontrol listesi, basit bir örnek ve sonraki adımlar
Sadece birkaç şey yapacaksanız, şu adımlarla başlayın:
- Her satır için kararlı, benzersiz bir id kullanın (dizi indeksi değil, görünüm içinde yeni oluşturulmuş UUID değil)
- Satır işini küçük tutun: ağır biçimlendirmelerden, büyük view ağaçlarından ve
bodyiçinde pahalı hesaplamalardan kaçının - Yayınları kontrol edin: hızlı değişen durumların (zamanlayıcılar, yazma, ağ ilerlemesi) tüm listeyi geçersiz kılmasına izin vermeyin
- Sayfalama ve ön getirme uygulayın ki bellek sabit kalsın
- Ölçmeden önce ve sonra Instruments ile test edin, tahmin etmeyin
Bir destek gelen kutusunu düşünün: 20.000 konuşma. Her satır konu, son mesaj önizlemesi, zaman damgası, okunmamış rozeti ve bir avatar gösterir. Kullanıcılar arama yapabilir ve yeni mesajlar kaydırırken gelebilir. Yavaş versiyon genelde birkaç şeyi aynı anda yapar: her tuş vuruşunda satırları yeniden kurar, metni çok sık ölçer ve çok fazla resmi çok erken fetch eder.
Kod tabanınızı baştan yıkmadan uygulanabilecek pratik plan:
- Temel: Kısa bir kaydırma ve arama oturumu kaydını Instruments'ta alın (Time Profiler + Core Animation).
- Kimliği düzeltin: modelinizde gerçek bir id olduğundan ve
ForEach'in bunu tutarlı kullandığından emin olun. - Sayfalama ekleyin: önce en yeni 50–100 öğeyi yükleyin, sonra kullanıcı sona yaklaştığında daha fazlasını alın.
- Resimleri optimize edin: küçük thumbnail'lar kullanın, önbellekleme yapın ve ana iş parçacığında dekodlamadan kaçının.
- Yeniden ölçüm: daha az düzen geçişi, daha az görünüm güncellemesi ve eski cihazlarda daha stabil kare süreleri doğrulayın.
Tam bir ürün (iOS uygulaması + backend + web admin paneli) inşa ediyorsanız, veri modeli ve sayfalama sözleşmesini erken tasarlamak da faydalıdır. AppMaster (appmaster.io) gibi platformlar bu tam-yığın iş akışı için tasarlanmıştır: veriyi ve iş mantığını görsel olarak tanımlamanıza izin verir ve yine de dağıtılabilir veya kendi kendinize barındırılabilir gerçek kaynak kodu oluşturur.
SSS
Önce satır kimliğini düzeltin. Modelinizden gelen kararlı bir id kullanın ve görünüm içinde ID üretmekten kaçının; çünkü ID değişirse SwiftUI satırları yeni olarak görür ve gereğinden fazla yeniden oluşturma yapar.
body yeniden hesaplaması genellikle ucuzdur; pahalı olan, bunun tetiklediği işlemlerdir. Ağır düzen hesaplaması, metin ölçümü, resim dekodlama ve kimliği değişken satırlar yüzünden yeniden oluşturulan çok sayıda satır genellikle kare düşmelerine yol açar.
Satır içinde UUID() kullanmayın veya verinin eklenip çıkarılabildiği durumlarda dizi indekslerine güvenmeyin. Tercihen sunucu/veritabanı ID'si veya model oluşturulduğunda saklanan bir UUID kullanın, böylece ID güncellemeler boyunca sabit kalır.
id: \.self performansı kötüleştirebilir, özellikle de elemanın hash'i düzenlenebilir alanlar güncellendiğinde değişiyorsa; çünkü SwiftUI bunu farklı bir satır olarak görebilir. Eğer Hashable kullanmanız gerekiyorsa, kimliği tek bir kararlı değere dayandırın, name, isSelected veya türetilmiş metin gibi düzenlenebilir alanlara dayandırmayın.
Ağır işleri body içinde yapmaktan kaçının. Tarih ve sayı biçimlendirmesini önceden yapın, her satır için yeni formatlayıcı oluşturmayın ve .map/.filter ile büyük türetilmiş diziler üretmek yerine bunları model veya view model içinde hesaplayıp hazır görüntü değerlerini satıra iletin.
onAppear kaydırma sırasında sıkça çalışır çünkü satırlar ekran girip çıktıkça tetiklenir. Her satır burada ağır işler (resim dekodlama, veritabanı okuma, parsing) başlatıyorsa tekrar eden zirveler oluşur; onAppear'ı sayfalama tetiklemek gibi ucuz işlemlerle sınırlayın.
Listeyi etkileyen veya ekran tarafından paylaşılan hızlı değişen herhangi bir yayımlanan değer, satırı sık sık geçersiz kılabilir. Zamanlayıcılar, yazma durumları ve ilerleme güncellemelerini ana listeyi yöneten nesnenin dışında tutun, aramayı debounce edin ve gerektiğinde büyük ObservableObject'leri daha küçük parçalara ayırın.
List klasik tablo benzeri ekranlar (metin, resim, kaydırma işlemleri, seçim, ayırıcılar) için genelde daha güvenlidir ve platform optimizasyonlarından yararlanır. ScrollView + LazyVStack ise özel düzenler için uygundur ama çok büyük veri setlerinde daha fazla bellek kullanımı ve takılma gösterebilir; hangisini kullanacağınızı tasarıma göre seçin ve ölçüm yapın.
Çok geç yüklemeye başlamak yerine kullanıcının son birkaç satıra geldiğinde yeni sayfayı başlatın, isLoading ve reachedEnd gibi koruyucular kullanın ve sonuçları kararlı ID'lerle çoğaltmayın. Bu, son satıra ulaştığında görülen beklemeleri önler.
Gerçek bir cihazda temel bir senaryo kaydedin ve Instruments ile ana iş parçacığı zirvelerini ve bellek tahsislerini inceleyin. Time Profiler, Allocations ve Core Animation kombinasyonu genellikle dar boğazın nerede olduğunu gösterir.


