@FetchRequest di SwiftUI — property wrapper untuk pengambilan data otomatis dari Core Data dengan pembaruan antarmuka reaktif. Wrapper menerima NSFetchRequest dengan predikat filter dan pengurutan, dan hasilnya — array NSManagedObject — diperbarui secara otomatis pada setiap perubahan di konteks Core Data. Menurut Apple Developer Documentation (2025), @FetchRequest memerlukan managedObjectContext di lingkungan SwiftUI dan mendukung predikat dinamis, menyediakan hubungan reaktif antara Core Data dan antarmuka pengguna.
Poin utama
@FetchRequest — adalah property wrapper SwiftUI yang membuat dan mengelola FetchRequest dari Core Data. Saat inisialisasi, wrapper menerima tipe entitas, array NSSortDescriptor untuk pengurutan, dan NSPredicate opsional untuk filtering. Hasilnya disimpan sebagai array objek dari tipe NSManagedObject yang ditentukan dan diperbarui secara otomatis saat ada perubahan di lapisan persistensi.
Fitur utama @FetchRequest adalah reaktivitas. Ketika data di Core Data berubah (save, insert, delete, update), SwiftUI secara otomatis melakukan pengambilan ulang dan menggambar ulang semua View yang menggunakan fetch request ini. Pengembang tidak perlu memanggil refresh secara manual, berlangganan ke NSManagedObjectContextDidSaveNotification, atau memuat ulang data. SwiftUI mengelola seluruh siklus sinkronisasi.
Untuk bekerja, @FetchRequest memerlukan NSManagedObjectContext yang tersedia di lingkungan SwiftUI melalui @Environment(\.managedObjectContext). Konteks biasanya diteruskan dari akar aplikasi tempat NSPersistentContainer dibuat. Pola standar — menggunakan ViewModel atau struktur App untuk mengonfigurasi tumpukan Core Data dan meneruskan konteks melalui pengubah .environment().
@FetchRequest menerima beberapa parameter untuk mengonfigurasi pengambilan. SortDescriptors — array NSSortDescriptor yang menentukan urutan catatan. Predicate — NSPredicate untuk filtering, misalnya, mengambil hanya tugas dengan status “selesai”. Animation — animasi untuk memperbarui daftar saat perubahan data.
Predikat Core Data menggunakan format ekspresi mirip SQL: NSPredicate(format: “status == %@”, “completed”). Beberapa kondisi dapat digabungkan melalui AND, OR, dan NOT. SortDescriptors menentukan urutan: NSSortDescriptor(keyPath: \Task.dueDate, ascending: true). Untuk pengurutan berdasarkan beberapa bidang, array deskriptor diteruskan — yang pertama diterapkan sebagai utama, sisanya sebagai sekunder.
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 ?? "")
}
}
}
Dalam contoh, @FetchRequest memilih semua tugas yang belum selesai (isCompleted == NO), diurutkan pertama berdasarkan tanggal (menaik), kemudian berdasarkan prioritas (menurun). FetchedResults<Task> — koleksi yang diperbarui secara otomatis yang berperilaku seperti array untuk ForEach dan List. Animasi .default memastikan kemunculan/penghilangan catatan yang mulus saat perubahan.
@FetchRequest sangat cocok dengan List dan ForEach untuk menampilkan daftar dinamis Core Data. Hasil pengambilan (FetchedResults) sesuai dengan protokol RandomAccessCollection, sehingga dapat digunakan langsung di List dan ForEach. Saat penambahan, penghapusan, atau perubahan catatan, daftar secara otomatis digambar ulang dengan animasi.
Untuk menghapus catatan, gunakan metode delete dari konteks. Untuk menambahkan — buat NSManagedObject baru dan panggil save. Semua perubahan dilakukan melalui viewContext, yang bersama dengan @FetchRequest memastikan konsistensi data. Untuk pengeditan, gunakan @ObservedObject atau @Bindable untuk objek Core Data tertentu.
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: "tambah") { 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()
}
}
Contoh ini mendemonstrasikan CRUD lengkap dengan @FetchRequest. Penambahan: membuat Task melalui konteks dan save(). Penghapusan: delete() pada konteks dan save(). Pembaruan: toggle properti dan save(). Setelah setiap save(), @FetchRequest secara otomatis meminta ulang data, dan List diperbarui dengan animasi. Pengubah onDelete dan onTapGesture menyediakan interaksi iOS standar.
@FetchRequest mendukung predikat dinamis melalui parameter predicate yang dapat diubah saat runtime. Untuk ini, Anda perlu membuat @FetchRequest dengan variabel-predikat dan meneruskannya melalui Binding. Ketika pengguna mengubah filter — misalnya, memilih kategori tugas — predikat diperbarui, dan pengambilan secara otomatis dimulai ulang.
Predikat dinamis diimplementasikan melalui properti @State atau @Published, yang diteruskan sebagai Binding ke inisialisator @FetchRequest. SwiftUI melacak perubahan Binding ini dan membuat ulang NSFetchRequest dengan predikat baru, secara otomatis memperbarui daftar.
Mari kita lihat contoh lengkap aplikasi jurnal dengan @FetchRequest untuk mengambil catatan. Formulir pencarian menggunakan predikat dinamis: saat memasukkan teks, FetchRequest secara otomatis memperbarui hasil, memfilter catatan berdasarkan judul dan konten. Pengurutan — berdasarkan tanggal pembuatan, dari terbaru ke terlama.
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)
}
}
Jurnal catatan dengan pencarian: saat memasukkan teks di bidang searchable, NSPredicate dengan CONTAINS[c] (pencarian tidak peka huruf besar/kecil) dibuat di bidang title dan content. Init menerima searchText dan membuat FetchRequest dengan predikat yang sesuai. Pengubah Searchable secara otomatis memperbarui searchText, dan @FetchRequest bereaksi terhadap perubahan predikat dan meminta ulang data.
Untuk skenario yang lebih kompleks dengan banyak filter, gabungkan NSCompoundPredicate dengan logika AND/OR. @FetchRequest mendukung predikat dengan kompleksitas apa pun, termasuk subquery bersarang (SUBQUERY) untuk pemfilteran berdasarkan relasi. Namun perlu diingat: predikat yang kompleks memengaruhi kinerja — untuk kumpulan data besar (lebih dari 10.000 catatan) gunakan pengindeksan Core Data dan batasi pengambilan melalui fetchLimit.
Pertanyaan yang sering diajukan
Tambahkan @Environment(\.managedObjectContext) var viewContext ke View root dan teruskan melalui pengubah .environment(\.managedObjectContext, context). Semua View anak yang menggunakan @FetchRequest akan secara otomatis mendapatkan konteks dari lingkungan.
Ya, ubah konteks Core Data: tambah, hapus, atau perbarui objek dan panggil save(). @FetchRequest akan secara otomatis melakukan pengambilan ulang dan memperbarui UI. Untuk pembaruan paksa tanpa save() gunakan viewContext.refreshAllObjects().
@FetchRequest mengembalikan array datar objek. @SectionedFetchRequest mengelompokkan hasil berdasarkan key path yang ditentukan ke dalam beberapa bagian, mirip dengan UITableView dengan sectionNameKeyPath. Gunakan @SectionedFetchRequest untuk daftar yang dikelompokkan dengan judul bagian.
Untuk pemfilteran berdasarkan relasi, gunakan notasi titik: NSPredicate(format: “category.name == %@”, “Work”). @FetchRequest secara otomatis melakukan JOIN di SQLite. Untuk mengakses relasi melalui objek yang dipilih, gunakan properti NSManagedObject biasa.
@FetchRequest tidak mendukung paginasi secara langsung, karena dirancang untuk menampilkan semua catatan dengan pembaruan reaktif. Untuk paginasi, gunakan NSFetchRequest dengan fetchLimit/fetchOffset dan muat data secara manual saat menggulir daftar.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga