Core Data هو إطار عمل من Apple لإدارة رسم بياني للكائنات في تطبيقات iOS و macOS. يوفر حفظ البيانات، تتبع التغييرات، التراجع عن العمليات والتكامل مع واجهة المستخدم عبر NSFetchedResultsController. وفقاً لوثائق Apple Developer (2025)، Core Data ليس قاعدة بيانات — بل هو طبقة نمذجة كائنات تستخدم افتراضياً SQLite كمخزن دائم لتحميل وحفظ الكائنات.
الخلاصة
Core Data هو إطار عمل لإدارة الرسم البياني للكائنات والحفظ الدائم، وهو جزء من Cocoa Touch SDK من Apple. يوفر واجهة موجهة للكائنات للعمل مع البيانات: يشتغل المطور مع الكيانات والسمات والعلاقات، بينما يحول Core Data هذه الكائنات إلى سجلات قاعدة بيانات علائقية تحت الغطاء.
تم تقديم Core Data في Mac OS X 10.4 Tiger (2005) لنظام macOS وتم نقله إلى iOS 3.0 (2009). على مدى أكثر من 20 عاماً، تطور الإطار من طبقة تجريد بسيطة فوق SQLite إلى رزمة كاملة مع دعم المزامنة السحابية عبر NSPersistentCloudKitContainer، وتعدد الخيوط من خلال الإدارة التلقائية للسياقات، والتحميل غير المتزامن عبر Swift Concurrency.
وفقاً لاستطلاع لمطوري iOS من Slack Community (2025)، يُستخدم Core Data في 68% من تطبيقات iOS التجارية للتخزين المحلي للبيانات. على الرغم من الانتقادات لتعقيده وطبقاته المتعددة، يبقى الإطار المعيار لتطبيقات Apple بفضل التكامل الوثيق مع النظام، والتكلفة الصفرية (مدمج في SDK)، ودعم المزامنة مع iCloud.
اعتقاد خاطئ شائع هو اعتبار Core Data قاعدة بيانات. الإطار لا ينفذ استعلامات SQL مباشرة وليس نظام إدارة قواعد بيانات. Core Data هو طبقة إدارة رسم بياني للكائنات يمكنها استخدام مخازن SQLite أو Binary أو In-Memory للحفظ الدائم. تشبيه: Core Data مثل Hibernate أو Entity Framework ولكن للنظام البيئي Apple، و SQLite تحته مثل MySQL تحت Hibernate.
رزمة Core Data تتكون من أربعة مكونات مترابطة: NSManagedObjectModel (مخطط البيانات)، NSPersistentStoreCoordinator (منسق المخازن)، NSManagedObjectContext (سياق العمل)، و NSPersistentContainer (حاوية موحدة تجمع الثلاثة منذ iOS 10). NSPersistentContainer يؤتمت إنشاء وتكوين الرزمة.
كل مكون يؤدي وظيفة محددة بدقة. NSManagedObjectModel يقوم بتحميل ملف .xcdatamodeld مع أوصاف الكيانات. NSPersistentStoreCoordinator يربط النموذج بملف المخزن الفعلي (SQLite). NSManagedObjectContext يوفر مساحة مؤقتة للعمل مع الكائنات. الحاوية توحد كل شيء في استدعاء تهيئة واحد.
SQLite (NSSQLiteStoreType) هو المخزن القياسي المستخدم في معظم التطبيقات. يتم حفظ البيانات في ملف .sqlite واحد مع دعم معاملات ACID. Binary (NSBinaryStoreType) هو مخزن بتنسيق ثنائي لمجموعات البيانات الصغيرة (حتى بضع مئات من الكائنات). In-Memory (NSInMemoryStoreType) هو مخزن مؤقت في RAM بدون حفظ على القرص، يُستخدم للاختبارات والتخزين المؤقت.
| نوع المخزن | التنسيق | الأداء | متى يُستخدم |
|---|---|---|---|
| SQLite | .sqlite | عالٍ | الخيار القياسي للإنتاج |
| Binary | .binary | متوسط | مجموعات بيانات صغيرة |
| In-Memory | RAM | أقصى | اختبارات، تخزين مؤقت، بيانات مؤقتة |
| CloudKit | iCloud | يعتمد على الشبكة | مزامنة عبر الأجهزة |
يتم تعيين نوع المخزن بسطر واحد عند تهيئة NSPersistentStoreDescription. يمكن للمطور التبديل من SQLite إلى In-Memory للاختبارات الوحدوية أو إلى CloudKit لمزامنة iCloud دون تغيير كود معالجة الكائنات — Core Data يجرد الفروق بين أنواع المخازن من خلال واجهة برمجة سياق موحدة.
NSManagedObject هو الفئة الأساسية لجميع كائنات Core Data، ويمثل سجلاً واحداً لكيان. كل كائن مُدار له NSManagedObjectID فريد (معرف دائم)، ومرتبط بسياق، ويتتبع تغييراته عبر KVO (مراقبة القيمة الرئيسية). ينشئ المطورون فئات فرعية من NSManagedObject لتحديد خصائص الكيان المكتوبة.
NSManagedObjectContext هو المكون المركزي لـ Core Data الذي يوفر مساحة عمل لجميع عمليات الكائنات. يتتبع السياق الإضافات والحذف والتغييرات (تتبع التغيير)، ويدعم التراجع عن العمليات عبر undoManager، ويدمج تلقائياً التغييرات من السياقات الأخرى عند تلقي إشعارات الحفظ.
قاعدة الطوابير الخاصة: يتم إنشاء NSManagedObjectContext بـ .privateQueueConcurrencyType أو .mainQueueConcurrencyType. السياق الرئيسي مرتبط بخيط واجهة المستخدم الرئيسي، بينما تعمل السياقات الخاصة على طوابير خلفية. يجب استخدام كل سياق فقط على طابوره الخاص — الوصول إلى كائن مُدار من خيط آخر يسبب تعطل التطبيق. parentContext يسمح بتنظيم تسلسل هرمي للسياقات للكتابة غير المتزامنة.
struct CoreDataStack {
let container: NSPersistentContainer
init(name: String) {
container = NSPersistentContainer(name: name)
container.loadPersistentStores { _, error in
if let error = error {
fatalError("Failed to load store: \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
}
func backgroundContext() -> NSManagedObjectContext {
let context = container.newBackgroundContext()
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
return context
}
}
NSPersistentContainer ينشئ تلقائياً viewContext (طابور رئيسي) ويوفر newBackgroundContext() للعمليات الخلفية. تعيين automaticallyMergesChangesFromParent = true يجعل viewContext يلتقط تلقائياً التغييرات من السياقات الخلفية عند حفظها، مما يحدث واجهة المستخدم دون إعادة جلب البيانات يدوياً.
NSPersistentStoreCoordinator يدير مخزن البيانات الفعلي: يفتح الملف، ينشئ جداول SQLite بناءً على النموذج، وينفذ الترحيلات عند تغيير المخطط. عند تهيئة NSPersistentStoreDescription بـ NSSQLiteStoreType، ينشئ Core Data ملف SQLite بمخطط يطابق نموذج .xcdatamodeld.
Core Data لا يستخدم استعلامات SQL القياسية عبر SELECT/INSERT/UPDATE. بدلاً من ذلك، يولد أوامر SQL داخلية بناءً على النموذج والاستعلامات التي تتم عبر NSFetchRequest. يمكن للمطور تفعيل تسجيل SQL عبر وسيط التشغيل -com.apple.CoreData.SQLDebug 1 لتصحيح أداء الاستعلامات.
الترحيل الخفيف (Lightweight Migration) هو عملية تلقائية لتحديث مخطط SQLite عند إضافة سمات جديدة، تغيير علامات optional/required أو إعادة التسمية باستخدام renamingID. الترحيل الثقيل مطلوب للتغييرات الجذرية في المخطط مثل دمج أو تقسيم الكيانات، ويتم عبر NSMigrationManager مخصص.
let description = NSPersistentStoreDescription()
description.url = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask)
.first?
.appendingPathComponent("Model.sqlite")
description.setOption(true as NSNumber,
forKey: NSMigratePersistentStoresAutomaticallyOption)
description.setOption(true as NSNumber,
forKey: NSInferMappingModelAutomaticallyOption)
let container = NSPersistentContainer(name: "AppModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { _, error in
if let error = error { print("Migration error: \(error)") }
}
إعداد الترحيل التلقائي عبر NSMigratePersistentStoresAutomaticallyOption و NSInferMappingModelAutomaticallyOption يسمح لـ Core Data بتحديث ملف SQLite بشكل مستقل عند إضافة سمات أو كيانات في نسخة جديدة من النموذج. إذا كان الترحيل غير ممكن، يرمي منسق المخزن خطأً مع وصف السبب — يجب على المطور تنفيذ ترحيل مخصص عبر NSMigrationManager.
NSFetchRequest هو الأداة الرئيسية لجلب الكائنات من Core Data. يحتوي الطلب على اسم الكيان، المُسند (عامل تصفية)، ترتيبات الفرز، الحد والإزاحة. يتم إرجاع النتيجة كمصفوفة من NSManagedObject أو فئات فرعية مكتوبة. NSPredicate يدعم شروطاً معقدة مع AND و OR و IN و LIKE والاستعلامات الفرعية.
NSBatchDeleteRequest هو طريقة فعالة لحذف الكائنات بشكل مجمع دون تحميل كل كائن في الذاكرة. يتم تنفيذ الطلب على مستوى SQLite، متجاوزاً سياق الكائن المُدار، ويحدث السياق فقط بعد الانتهاء. توجد طلبات مجمعة مماثلة للتحديث (NSBatchUpdateRequest) والإدراج (NSBatchInsertRequest).
CRUD (إنشاء، قراءة، تحديث، حذف) في Core Data يتم عبر طرق السياق: insert و fetch و save و delete. جميع التغييرات مؤقتة حتى استدعاء context.save() — هذه الطريقة تحفظ التغييرات في مخزن SQLite الدائم. عند خطأ في الحفظ، يبقى السياق في حالته المعدلة لإعادة المحاولة.
let context = container.viewContext
// إنشاء
let user = User(context: context)
user.id = 42
user.name = "Alice"
// قراءة
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "name CONTAINS %@", "Ali")
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let results = try context.fetch(request)
// تحديث
results.first?.name = "Alice Updated"
// حذف
if let first = results.first { context.delete(first) }
// حفظ
try context.save()
حفظ السياق (context.save()) هو عملية حرجة. إذا لم يتم استدعاء save، تبقى جميع التغييرات في الذاكرة فقط. يتتبع السياق حالة hasChanges، والتي يمكن التحقق منها قبل الحفظ. للعمليات الخلفية، استخدم newBackgroundContext مع حفظ خاص به، وللواجهة، استخدم viewContext مع حفظ تلقائي عبر مؤقت أو عند دخول التطبيق إلى الخلفية.
الممارسة الأولى — استخدم NSPersistentCloudKitContainer لمزامنة البيانات عبر أجهزة المستخدم عبر iCloud. يتم تفعيل المزامنة السحابية بإضافة خيار CloudKit إلى وصف المخزن الدائم. Core Data يدير تلقائياً تعارضات المزامنة ويدمج التغييرات من الأجهزة الأخرى.
الممارسة الثانية — تجنب fetchRequest بدون مُسند على الجداول الكبيرة. كل جلب غير مشروط يحمل جميع كائنات الكيان إلى الذاكرة، مما يؤدي إلى استهلاك عالٍ للذاكرة وتباطؤ واجهة المستخدم. استخدم دائماً المُسندات والحدود. للترحيل، استخدم fetchLimit و fetchOffset في NSFetchRequest.
الممارسة الثالثة — قم بتكوين mergePolicy لحل التعارضات في الوصول متعدد الخيوط. NSMergeByPropertyObjectTrumpMergePolicy يحدث الخصائص المتعارضة من آخر سياق تم حفظه. NSRollbackMergePolicy يتجاهل تغييرات السياق الحالي عند التعارض. اختيار السياسة يعتمد على منطق الأعمال للتطبيق.
الممارسة الرابعة — استخدم NSFetchedResultsController للتكامل مع الجداول والمجموعات. يشترك تلقائياً في إشعارات NSManagedObjectContextDidSave، ويحمل فقط الكائنات الضرورية (faulting)، ويخطر المفوض بالإدراجات والحذف والتحركات مع مسارات الفهارس المناسبة لتحريك UITableView.
Faulting هي آلية التحميل البطيء لـ Core Data. الكائن المُدار الذي يتم إرجاعه بواسطة طلب جلب يكون في حالة fault — سماته غير محملة بالكامل، فقط المعرف. التحميل الكامل (fire fault) يحدث عند أول وصول لأي سمة. الجلب المسبق للعلاقات (setRelationshipKeyPathsForPrefetching) يحمل الكائنات المرتبطة مسبقاً، متجنباً استعلامات N+1.
extension UserRepository {
func fetchUsersWithPosts() throws -> [User] {
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "isActive == YES")
request.relationshipKeyPathsForPrefetching = ["posts"]
request.returnsObjectsAsFaults = false
request.fetchBatchSize = 20
let context = container.viewContext
return try context.fetch(request)
}
}
fetchBatchSize = 20 يجعل Core Data يحمل البيانات بدفعات من 20 كائناً (لعرضها على الشاشة)، دون تحميل الجدول بأكمله مرة واحدة. العلم returnsObjectsAsFaults = false يضمن تحميل جميع سمات المستخدم فوراً، وهو مفيد للعرض المباشر. الجلب المسبق للعلاقة “posts” يتجنب الاستعلامات المنفصلة لكل مستخدم عند الوصول إلى المنشورات.
الأسئلة الشائعة
لا، Core Data هو إطار لإدارة الرسم البياني للكائنات. يوفر واجهة برمجة للعمل مع الكائنات وتتبع التغييرات وحفظها. قاعدة البيانات تحت غطاء Core Data (SQLite افتراضياً) لا يجب الخلط بينها وبين الإطار نفسه. Core Data هو ORM، وليس نظام إدارة قواعد بيانات.
نعم، Core Data يدعم ثلاثة أنواع من المخازن: SQLite و Binary و In-Memory. يتم تعيين نوع المخزن عبر NSPersistentStoreDescription. مخزن In-Memory لا يحفظ البيانات على القرص ومناسب للاختبارات الوحدوية. مخزن Binary هو تنسيق قديم لمجموعات الكائنات المدمجة.
للترحيل الخفيف، فعّل NSMigratePersistentStoresAutomaticallyOption و NSInferMappingModelAutomaticallyOption. للتغييرات المعقدة، أنشئ Mapping Model (.xcmappingmodel) عبر Xcode. مخزن CloudKit (NSPersistentCloudKitContainer) يدعم الترحيلات تلقائياً عند مزامنة المخطط مع خادم iCloud.
SwiftData هو إطار Apple جديد (iOS 17+) مبني فوق Core Data باستخدام Swift Macros و Swift Concurrency. SwiftData له بناء جملة أبسط: تُوصف الكيانات بالماكرو @Model، والسياق بـ @Environment(\.modelContext). تحت الغطاء، يستخدم SwiftData نفس رزمة Core Data و SQLite.
فعّل وسيط التشغيل -com.apple.CoreData.SQLDebug 1 — سيقوم Core Data بإخراج جميع استعلامات SQL ومدتها في وحدة تحكم Xcode. للتحليل، استخدم Instruments مع قالب Core Data، الذي يظهر عدد طلبات fault وأوقات تحميل الكائنات ومدة حفظ السياق.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.