SwiftUI-এ @FetchRequest — একটি property wrapper যা Core Data থেকে স্বয়ংক্রিয়ভাবে ডেটা ফেচ করে এবং রিঅ্যাকটিভভাবে UI আপডেট করে। Wrapper ফিল্টার প্রেডিকেট এবং সর্ট ডিসক্রিপ্টর সহ NSFetchRequest গ্রহণ করে, এবং ফলাফল — NSManagedObject-এর একটি অ্যারে — Core Data কনটেক্সটে যেকোনো পরিবর্তনে স্বয়ংক্রিয়ভাবে আপডেট হয়। Apple Developer Documentation (2025) অনুযায়ী, @FetchRequest-এর SwiftUI পরিবেশে managedObjectContext প্রয়োজন এবং এটি ডায়নামিক প্রেডিকেট সমর্থন করে, যা Core Data এবং ইউজার ইন্টারফেসের মধ্যে রিঅ্যাকটিভ সংযোগ নিশ্চিত করে।
মূল পয়েন্ট
@FetchRequest একটি SwiftUI property wrapper যা Core Data থেকে FetchRequest তৈরি এবং পরিচালনা করে। ইনিশিয়ালাইজেশনে, wrapper একটি entity type, সর্টিংয়ের জন্য NSSortDescriptor-এর অ্যারে এবং ফিল্টারিংয়ের জন্য একটি অপশনাল NSPredicate গ্রহণ করে। ফলাফল নির্দিষ্ট NSManagedObject টাইপের অবজেক্টের অ্যারে হিসেবে সংরক্ষিত হয় এবং persistence layer-এ পরিবর্তন হলে স্বয়ংক্রিয়ভাবে আপডেট হয়।
@FetchRequest-এর মূল বৈশিষ্ট্য হল রিঅ্যাকটিভিটি। যখন Core Data-তে ডেটা পরিবর্তিত হয় (save, insert, delete, update), SwiftUI স্বয়ংক্রিয়ভাবে পুনরায় ফেচ করে এবং এই fetch request ব্যবহার করে এমন সমস্ত Views পুনরায় রেন্ডার করে। ডেভেলপারকে ম্যানুয়ালি refresh কল করতে, NSManagedObjectContextDidSaveNotification-এ সাবস্ক্রাইব করতে বা ডেটা রিলোড করার প্রয়োজন নেই। SwiftUI সম্পূর্ণ সিঙ্ক্রোনাইজেশন চক্র পরিচালনা করে।
@FetchRequest কাজ করার জন্য, SwiftUI পরিবেশে @Environment(\.managedObjectContext)-এর মাধ্যমে একটি NSManagedObjectContext উপলব্ধ থাকা প্রয়োজন। কনটেক্সট সাধারণত অ্যাপ্লিকেশন রুট থেকে পাস করা হয়, যেখানে NSPersistentContainer তৈরি করা হয়। স্ট্যান্ডার্ড প্যাটার্ন হল Core Data স্ট্যাক কনফিগার করতে এবং .environment() মডিফায়ারের মাধ্যমে কনটেক্সট পাস করতে ViewModel বা App struct ব্যবহার করা।
@FetchRequest ফেচ কনফিগার করার জন্য বেশ কয়েকটি প্যারামিটার গ্রহণ করে। SortDescriptors — NSSortDescriptor-এর অ্যারে যা রেকর্ডের ক্রম নির্ধারণ করে। Predicate — ফিল্টারিংয়ের জন্য NSPredicate, উদাহরণস্বরূপ, শুধুমাত্র “সম্পূর্ণ” স্ট্যাটাসের টাস্ক ফেচ করা। Animation — ডেটা পরিবর্তনে তালিকা আপডেটের জন্য অ্যানিমেশন।
Core Data প্রেডিকেট SQL-সদৃশ এক্সপ্রেশনের ফরম্যাট ব্যবহার করে: NSPredicate(format: “status == %@”, “completed”)। AND, OR এবং NOT-এর মাধ্যমে একাধিক শর্ত একত্রিত করা যায়। SortDescriptors ক্রম নির্ধারণ করে: NSSortDescriptor(keyPath: \Task.dueDate, ascending: true)। একাধিক ফিল্ড দ্বারা সর্ট করতে, ডিসক্রিপ্টরের অ্যারে পাস করা হয় — প্রথমটি প্রাথমিক হিসেবে প্রয়োগ হয়, বাকিগুলো গৌণ হিসেবে।
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 ?? "")
}
}
}
উদাহরণে, @FetchRequest সব অসম্পূর্ণ টাস্ক (isCompleted == NO) ফেচ করে, প্রথমে তারিখ অনুসারে (ascending), তারপর প্রায়োরিটি অনুসারে (descending) সাজানো। FetchedResults<Task> একটি স্বয়ংক্রিয়ভাবে আপডেট হওয়া সংগ্রহ যা ForEach এবং List-এর জন্য অ্যারের মতো আচরণ করে। .default অ্যানিমেশন পরিবর্তনে রেকর্ডের মসৃণ উপস্থিতি/অদৃশ্যতা নিশ্চিত করে।
@FetchRequest ডায়নামিক Core Data তালিকা প্রদর্শনের জন্য List এবং ForEach-এর সাথে পুরোপুরি মিলে যায়। ফেচ ফলাফল (FetchedResults) RandomAccessCollection প্রোটোকল মেনে চলে, তাই এটি List এবং ForEach-এ সরাসরি ব্যবহার করা যায়। রেকর্ড যোগ, মুছে বা পরিবর্তন করলে, তালিকা স্বয়ংক্রিয়ভাবে অ্যানিমেশনসহ পুনরায় রেন্ডার হয়।
রেকর্ড মুছতে, কনটেক্সট মেথড delete ব্যবহার করা হয়। রেকর্ড যোগ করতে, একটি নতুন NSManagedObject তৈরি করা হয় এবং save কল করা হয়। সব পরিবর্তন viewContext-এর মাধ্যমে করা হয়, যা @FetchRequest-এর সাথে ডেটা সামঞ্জস্য নিশ্চিত করে। এডিটিংয়ের জন্য, একটি নির্দিষ্ট Core Data অবজেক্টের জন্য @ObservedObject বা @Bindable ব্যবহার করা হয়।
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()
}
}
এই উদাহরণটি @FetchRequest-এর সাথে সম্পূর্ণ CRUD প্রদর্শন করে। যোগ: কনটেক্সটের মাধ্যমে Task তৈরি এবং save()। মুছে ফেলা: কনটেক্সটে delete() এবং save()। আপডেট: প্রপার্টি টগল এবং save()। প্রতিটি save()-এর পর, @FetchRequest স্বয়ংক্রিয়ভাবে ডেটা পুনরায় ফেচ করে, এবং List অ্যানিমেটেডভাবে আপডেট হয়। onDelete এবং onTapGesture মডিফায়ারগুলি স্ট্যান্ডার্ড iOS ইন্টারঅ্যাকশন প্রদান করে।
আসুন রেকর্ড ফেচের জন্য @FetchRequest-সহ একটি সম্পূর্ণ জার্নাল অ্যাপ্লিকেশন উদাহরণ দেখি। সার্চ ফর্ম একটি ডায়নামিক প্রেডিকেট ব্যবহার করে: টেক্সট ইনপুট করলে, FetchRequest স্বয়ংক্রিয়ভাবে ফলাফল আপডেট করে, শিরোনাম এবং বিষয়বস্তু অনুসারে রেকর্ড ফিল্টার করে। সর্টিং তৈরি হওয়ার তারিখ অনুসারে, নতুন থেকে পুরাতন।
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)
}
}
সার্চসহ জার্নাল: searchable ফিল্ডে টেক্সট ইনপুট করলে, title এবং content ফিল্ডে CONTAINS[c] (কেস-অসংবেদনশীল সার্চ) সহ একটি NSPredicate তৈরি হয়। Init searchText গ্রহণ করে এবং সংশ্লিষ্ট প্রেডিকেটসহ FetchRequest তৈরি করে। Searchable মডিফায়ার স্বয়ংক্রিয়ভাবে searchText আপডেট করে, এবং @FetchRequest প্রেডিকেট পরিবর্তনে সাড়া দিয়ে ডেটা পুনরায় ফেচ করে।
একাধিক ফিল্টারসহ আরও জটিল পরিস্থিতির জন্য, AND/OR লজিকের সাথে NSCompoundPredicate একত্রিত করুন। @FetchRequest যেকোনো জটিলতার প্রেডিকেট সমর্থন করে, যার মধ্যে relationship দ্বারা ফিল্টার করার জন্য নেস্টেড সাবকোয়েরি (SUBQUERY) অন্তর্ভুক্ত। তবে মনে রাখবেন: জটিল প্রেডিকেট পারফরম্যান্সকে প্রভাবিত করে — বড় ডেটাসেটের (10,000-এর বেশি রেকর্ড) জন্য, Core Data ইন্ডেক্সিং ব্যবহার করুন এবং fetchLimit-এর মাধ্যমে ফেচ সীমিত করুন।
@FetchRequest predicate প্যারামিটারের মাধ্যমে ডায়নামিক প্রেডিকেট সমর্থন করে, যা রানটাইমে পরিবর্তন করা যায়। এর জন্য, একটি ভেরিয়েবল প্রেডিকেটসহ @FetchRequest তৈরি করা হয় এবং Binding-এর মাধ্যমে পাস করা হয়। যখন ব্যবহারকারী ফিল্টার পরিবর্তন করে — উদাহরণস্বরূপ, একটি টাস্ক ক্যাটাগরি নির্বাচন করে — প্রেডিকেট আপডেট হয় এবং ফেচ স্বয়ংক্রিয়ভাবে পুনরায় শুরু হয়।
ডায়নামিক প্রেডিকেট @State বা @Published প্রপার্টির মাধ্যমে বাস্তবায়িত হয়, যা @FetchRequest ইনিশিয়ালাইজারে Binding হিসেবে পাস করা হয়। SwiftUI এই Binding-এর পরিবর্তন ট্র্যাক করে এবং নতুন প্রেডিকেটসহ NSFetchRequest পুনরায় তৈরি করে, স্বয়ংক্রিয়ভাবে তালিকা আপডেট করে।
সচরাচর জিজ্ঞাসিত প্রশ্ন
রুট View-এ @Environment(\.managedObjectContext) var viewContext যোগ করুন এবং .environment(\.managedObjectContext, context) মডিফায়ারের মাধ্যমে পাস করুন। @FetchRequest ব্যবহার করে এমন সব চাইল্ড Views স্বয়ংক্রিয়ভাবে পরিবেশ থেকে কনটেক্সট পাবে।
হ্যাঁ, Core Data কনটেক্সট পরিবর্তন করুন: একটি অবজেক্ট যোগ, মুছে বা আপডেট করুন এবং save() কল করুন। @FetchRequest স্বয়ংক্রিয়ভাবে পুনরায় ফেচ করবে এবং UI আপডেট করবে। save() ছাড়া জোর করে আপডেটের জন্য, viewContext.refreshAllObjects() ব্যবহার করুন।
@FetchRequest অবজেক্টের একটি ফ্ল্যাট অ্যারে রিটার্ন করে। @SectionedFetchRequest ফলাফলগুলিকে নির্দিষ্ট key path অনুসারে sectionNameKeyPath-সহ UITableView-এর মতো সেকশনে গ্রুপ করে। সেকশন হেডারসহ grouped তালিকার জন্য @SectionedFetchRequest ব্যবহার করুন।
relationship দ্বারা ফিল্টার করতে, ডট নোটেশন ব্যবহার করুন: NSPredicate(format: “category.name == %@”, “Work”)। @FetchRequest স্বয়ংক্রিয়ভাবে SQLite-এ JOIN করে। নির্বাচিত অবজেক্টের মাধ্যমে relationship অ্যাক্সেস করতে, সাধারণ NSManagedObject প্রপার্টি ব্যবহার করুন।
@FetchRequest সরাসরি পেজিনেশন সমর্থন করে না, কারণ এটি রিঅ্যাকটিভ আপডেটসহ সব রেকর্ড প্রদর্শনের জন্য ডিজাইন করা হয়েছে। পেজিনেশনের জন্য, fetchLimit/fetchOffset-সহ NSFetchRequest ব্যবহার করুন এবং তালিকা স্ক্রল করার সময় ম্যানুয়ালি ডেটা লোড করুন।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন