SwiftUI'da @FetchRequest — Core Data'dan otomatik olarak veri çeken ve reaktif arayüz güncellemesi sağlayan bir property wrapper'dır. Wrapper, filtre koşulları ve sıralamalarla NSFetchRequest'i kabul eder ve sonuç — NSManagedObject dizisi — Core Data bağlamındaki herhangi bir değişiklikte otomatik olarak güncellenir. Apple Developer Documentation (2025)'a göre, @FetchRequest SwiftUI ortamında managedObjectContext gerektirir ve dinamik koşulları destekleyerek Core Data ile kullanıcı arayüzü arasında reaktif bir bağlantı sağlar.
Önemli Noktalar
@FetchRequest, Core Data'dan FetchRequest oluşturan ve yöneten bir SwiftUI property wrapper'ıdır. Başlatma sırasında wrapper, bir varlık türü, sıralama için NSSortDescriptor dizisi ve filtreleme için isteğe bağlı bir NSPredicate kabul eder. Sonuç, belirtilen NSManagedObject türündeki nesnelerin bir dizisi olarak saklanır ve kalıcılık katmanında değişiklik olduğunda otomatik olarak güncellenir.
@FetchRequest'in temel özelliği reaktivitedir. Core Data'daki veriler değiştiğinde (save, insert, delete, update), SwiftUI otomatik olarak yeniden çekme yapar ve bu fetch request'i kullanan tüm View'ları yeniden çizer. Geliştiricinin manuel olarak refresh çağırmasına, NSManagedObjectContextDidSaveNotification'a abone olmasına veya verileri yeniden yüklemesine gerek yoktur. SwiftUI tüm senkronizasyon döngüsünü yönetir.
@FetchRequest'in çalışması için, SwiftUI ortamında @Environment(\.managedObjectContext) aracılığıyla bir NSManagedObjectContext kullanılabilir olmalıdır. Bağlam genellikle NSPersistentContainer'ın oluşturulduğu uygulama kökünden iletilir. Standart desen, Core Data yığınını yapılandırmak ve .environment() değiştiricisi aracılığıyla bağlamı iletmek için bir ViewModel veya App struct kullanmaktır.
@FetchRequest, çekmeyi yapılandırmak için birkaç parametre kabul eder. SortDescriptors — kayıtların sırasını belirleyen NSSortDescriptor dizisi. Predicate — filtreleme için NSPredicate, örneğin yalnızca durumu “tamamlandı” olan görevleri çekmek. Animation — veriler değiştiğinde listeyi güncellemek için animasyon.
Core Data koşulları, SQL benzeri ifadeler biçimini kullanır: NSPredicate(format: “status == %@”, “completed”). AND, OR ve NOT ile birden çok koşul birleştirilebilir. SortDescriptors sırayı tanımlar: NSSortDescriptor(keyPath: \Task.dueDate, ascending: true). Birden çok alana göre sıralamak için, bir tanımlayıcı dizisi iletilir — ilki birincil, geri kalanı ikincil olarak uygulanır.
struct TaskListView: View {
@Environment(\.managedObjectContext) var viewContext
@FetchRequest(
sortDescriptors: [
NSSortDescriptor(keyPath: \.Task.dueDate, ascending: true),
NSSortDescriptor(keyPath: \.Task.priority, ascending: false)
],
predicate: NSPredicate(format: "isCompleted == NO"),
animation: .default
)
var tasks: FetchedResults<Task>
var body: some View {
List(tasks) { task in
Text(task.title ?? "")
}
}
}
Örnekte, @FetchRequest tamamlanmamış tüm görevleri (isCompleted == NO) getirir, önce tarihe (artan), sonra önceliğe (azalan) göre sıralanır. FetchedResults<Task>, ForEach ve List için bir dizi gibi davranan otomatik güncellenen bir koleksiyondur. .default animasyonu, değişikliklerde kayıtların yumuşak bir şekilde görünmesini/kaybolmasını sağlar.
@FetchRequest, dinamik Core Data listelerini görüntülemek için List ve ForEach ile mükemmel şekilde birleşir. Çekme sonucu (FetchedResults), RandomAccessCollection protokolüne uygundur, bu nedenle List ve ForEach'te doğrudan kullanılabilir. Kayıtlar eklendiğinde, silindiğinde veya değiştirildiğinde, liste otomatik olarak animasyonla yeniden çizilir.
Kayıtları silmek için bağlam yöntemi delete kullanılır. Kayıt eklemek için yeni bir NSManagedObject oluşturulur ve save çağrılır. Tüm değişiklikler, @FetchRequest ile birlikte veri tutarlılığını sağlayan viewContext aracılığıyla gerçekleştirilir. Düzenleme için, belirli bir Core Data nesnesi için @ObservedObject veya @Bindable kullanılır.
struct TaskListWithActions: View {
@Environment(\.managedObjectContext) var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \.Task.createdAt,
ascending: false)]
)
var tasks: FetchedResults<Task>
var body: some View {
List {
ForEach(tasks) { task in
HStack {
Text(task.title ?? "")
Spacer()
Image(systemName: task.isCompleted
? "checkmark.circle.fill"
: "circle")
}
.onTapGesture { toggleTask(task) }
}
.onDelete(perform: deleteTasks)
}
.toolbar {
Button(systemImage: "plus") { addTask() }
}
}
private func addTask() {
let newTask = Task(context: viewContext)
newTask.title = "New task \(tasks.count + 1)"
newTask.createdAt = Date()
try? viewContext.save()
}
private func toggleTask(_ task: Task) {
task.isCompleted.toggle()
try? viewContext.save()
}
private func deleteTasks(at offsets: IndexSet) {
for index in offsets {
viewContext.delete(tasks[index])
}
try? viewContext.save()
}
}
Bu örnek, @FetchRequest ile tam CRUD'u gösterir. Ekleme: bağlam aracılığıyla Task oluşturma ve save(). Silme: bağlamda delete() ve save(). Güncelleme: bir özelliği değiştirme ve save(). Her save()'den sonra, @FetchRequest otomatik olarak verileri yeniden çeker ve List animasyonlu olarak güncellenir. onDelete ve onTapGesture değiştiricileri standart iOS etkileşimlerini sağlar.
Kayıtları çekmek için @FetchRequest ile tam bir günlük uygulaması örneğine bakalım. Arama formu dinamik bir koşul kullanır: metin girildiğinde, FetchRequest otomatik olarak sonuçları günceller ve kayıtları başlık ve içeriğe göre filtreler. Sıralama, oluşturma tarihine göre, yeniden eskiye doğrudur.
struct JournalEntryView: View {
@Environment(\.managedObjectContext) var viewContext
@State private var searchText = ""
private var searchPredicate: NSPredicate? {
guard !searchText.isEmpty else { return nil }
return NSPredicate(format: "title CONTAINS[c] %@", searchText)
}
@FetchRequest var entries: FetchedResults<JournalEntry>
init(searchText: String) {
let sort = [NSSortDescriptor(keyPath: \.JournalEntry.date,
ascending: false)]
let pred: NSPredicate? = searchText.isEmpty
? nil
: NSPredicate(format: "title CONTAINS[c] %@ OR content CONTAINS[c] %@",
searchText, searchText)
self._entries = FetchRequest(
sortDescriptors: sort,
predicate: pred,
animation: .default
)
}
var body: some View {
List(entries) { entry in
VStack(alignment: .leading) {
Text(entry.title ?? "").font(.headline)
Text(entry.content ?? "").font(.subheadline)
.lineLimit(2)
}
}
.searchable(text: $searchText)
}
}
Aramalı günlük: searchable alanına metin girildiğinde, title ve content alanlarında CONTAINS[c] (büyük/küçük harf duyarsız arama) ile bir NSPredicate oluşturulur. Init, searchText'i kabul eder ve ilgili koşulla bir FetchRequest oluşturur. Searchable değiştiricisi otomatik olarak searchText'i günceller ve @FetchRequest koşul değişikliğine tepki vererek verileri yeniden çeker.
Birden çok filtreli daha karmaşık senaryolar için, AND/OR mantığıyla NSCompoundPredicate'i birleştirin. @FetchRequest, ilişkiye göre filtreleme için iç içe alt sorgular (SUBQUERY) dahil olmak üzere herhangi bir karmaşıklıktaki koşulları destekler. Ancak unutmayın: karmaşık koşullar performansı etkiler — büyük veri kümeleri için (10.000'den fazla kayıt), Core Data indekslemeyi kullanın ve fetchLimit aracılığıyla çekmeyi sınırlayın.
@FetchRequest, çalışma zamanında değiştirilebilen predicate parametresi aracılığıyla dinamik koşulları destekler. Bunun için, değişken bir koşulla @FetchRequest oluşturulur ve Binding aracılığıyla iletilir. Kullanıcı filtreyi değiştirdiğinde — örneğin, bir görev kategorisi seçtiğinde — koşul güncellenir ve çekme otomatik olarak yeniden başlar.
Dinamik koşullar, @FetchRequest başlatıcısına Binding olarak iletilen bir @State veya @Published özelliği aracılığıyla uygulanır. SwiftUI, bu Binding'deki değişiklikleri izler ve yeni koşulla NSFetchRequest'i yeniden oluşturarak listeyi otomatik olarak günceller.
Sıkça Sorulan Sorular
Kök View'a @Environment(\.managedObjectContext) var viewContext ekleyin ve .environment(\.managedObjectContext, context) değiştiricisi aracılığıyla iletin. @FetchRequest kullanan tüm alt View'lar, ortamdan otomatik olarak bağlamı alır.
Evet, Core Data bağlamını değiştirin: bir nesne ekleyin, silin veya güncelleyin ve save() çağırın. @FetchRequest otomatik olarak yeniden çeker ve arayüzü günceller. save() olmadan zorunlu güncelleme için viewContext.refreshAllObjects() kullanın.
@FetchRequest, düz bir nesne dizisi döndürür. @SectionedFetchRequest, sonuçları belirtilen bir anahtar yola göre sectionNameKeyPath ile UITableView'e benzer şekilde bölümlere ayırır. Bölüm başlıkları olan gruplandırılmış listeler için @SectionedFetchRequest kullanın.
İlişkiye göre filtrelemek için nokta notasyonu kullanın: NSPredicate(format: “category.name == %@”, “Work”). @FetchRequest, SQLite'da otomatik olarak JOIN gerçekleştirir. Seçilen bir nesne aracılığıyla ilişkiye erişmek için normal NSManagedObject özelliklerini kullanın.
@FetchRequest, doğrudan sayfalamayı desteklemez çünkü reaktif güncellemeyle tüm kayıtları görüntülemek için tasarlanmıştır. Sayfalama için, fetchLimit/fetchOffset ile NSFetchRequest kullanın ve liste kaydırıldığında verileri manuel olarak yükleyin.
Özet
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.
Ayrıca okuyun