Core Data เป็นเฟรมเวิร์กการจัดการข้อมูลจาก Apple ที่ให้การแมปเชิงวัตถุ-เชิงสัมพันธ์สำหรับ iOS, macOS, tvOS และ watchOS โดยจะทำให้การบันทึก การดึงข้อมูล และการกรองวัตถุในแอปพลิเคชันเป็นอัตโนมัติ ทำงานบน SQLite, XML หรือที่เก็บข้อมูลแบบไบนารี ตาม Apple Core Data Documentation เฟรมเวิร์กใช้แนวคิด Managed Object Context และ NSPersistentContainer ในการจัดการสแต็กความคงทน
ประเด็นสำคัญ
Core Data เป็นเฟรมเวิร์กการจัดการกราฟวัตถุและความคงทนที่เป็นส่วนหนึ่งของ Cocoa Touch ซึ่งตรงข้ามกับความเข้าใจผิดที่พบบ่อย Core Data ไม่ใช่ฐานข้อมูล แต่เป็นชั้นการจัดการวัตถุที่สามารถใช้ SQLite เป็นหนึ่งในที่เก็บข้อมูล ภารกิจหลักของ Core Data คือการติดตามการเปลี่ยนแปลงของวัตถุ จัดการวงจรชีวิต และซิงโครไนซ์สถานะกับดิสก์
เฟรมเวิร์กมี กราฟวัตถุ โดยที่ Managed Object แต่ละตัวจะถูกติดตามโดยคอนเทกซ์เพื่อหาการเปลี่ยนแปลง เมื่อบันทึก วัตถุที่ถูกแก้ไข เพิ่ม และลบทั้งหมดจะถูกคอมมิตไปยังที่เก็บถาวรในธุรกรรมเดียว ซึ่งช่วยลดความจำเป็นที่นักพัฒนาจะต้องเขียนคำสั่ง SQL และจัดการธุรกรรมด้วยตนเอง
ตามสถิติของ Swift Developer Survey (2025) Core Data ถูกใช้ใน 52% ของแอปพลิเคชัน iOS ที่ทำงานกับข้อมูลท้องถิ่น แม้จะมีทางเลือกสมัยใหม่อย่าง SwiftData และ Realm แต่ Core Data ยังคงเป็นเฟรมเวิร์กหลักในโปรเจกต์ Apple ที่มีอยู่ เนื่องจากความสมบูรณ์และการรวมเข้ากับระบบอย่างลึกซึ้ง
ใช้ Core Data สำหรับโปรเจกต์ที่มีโมเดลข้อมูลความซับซ้อนระดับกลาง ซึ่งต้องการความสัมพันธ์ระหว่างวัตถุ การย้อนกลับการเปลี่ยนแปลง และแคชอัตโนมัติผ่านกลไก faulting
สถาปัตยกรรม Core Data สร้างขึ้นรอบแนวคิดของ Managed Object Context — พื้นที่ทำงานที่ติดตามการเปลี่ยนแปลงของวัตถุทั้งหมด คอนเทกซ์รองรับการเลิกทำ/ทำซ้ำผ่าน NSUndoManager ในตัว ซึ่งช่วยให้สามารถร่างและยกเลิกการกระทำได้โดยไม่ต้องบันทึกภาพสแนปชอตสถานะด้วยตนเอง เมื่อเรียก save() คอนเทกซ์จะคอมมิตการเปลี่ยนแปลงทั้งหมดในธุรกรรมเดียวไปยังที่เก็บถาวร รับประกันความเป็นอะตอมและความสอดคล้องของข้อมูล
โมเดลข้อมูล Core Data ถูกกำหนดในไฟล์ .xcdatamodeld — ตัวแก้ไขแบบภาพของ Xcode ซึ่งอธิบาย Entity, คุณลักษณะและความสัมพันธ์ทั้งหมด เมื่อคอมไพล์ โมเดลจะถูกทำให้เป็นลำดับเป็น .momd และโหลดผ่าน NSManagedObjectModel
Entity คือคำอธิบายชนิดข้อมูล คล้ายกับตารางใน SQL แต่ละ Entity ประกอบด้วย Attributes — ฟิลด์ที่มีชื่อพร้อมชนิดข้อมูล (String, Integer, Date, Boolean, Data) ซึ่งแตกต่างจาก Room Core Data ต้องการการเลือกชนิดอย่างชัดเจนสำหรับแต่ละคุณลักษณะผ่านตัวแก้ไขโมเดล
Relationship คือการเชื่อมต่อระหว่าง Entity คล้ายกับคีย์นอกใน SQL Core Data รองรับความสัมพันธ์ทุกประเภท: หนึ่งต่อหนึ่ง หนึ่งต่อหลาย และหลายต่อหลาย สำหรับแต่ละความสัมพันธ์จะมีการกำหนดค่า Delete Rule (Cascade, Nullify, Deny) — พฤติกรรมเมื่อลบวัตถุที่เกี่ยวข้อง
| Delete Rule | พฤติกรรมเมื่อลบ | ตัวอย่างการใช้งาน |
|---|---|---|
| Cascade | ลบวัตถุที่เกี่ยวข้องทั้งหมด | ลบคำสั่งซื้อพร้อมกับรายการ |
| Nullify | ตั้งค่าความสัมพันธ์ย้อนกลับเป็น null | ลบผู้เขียนโดยไม่ลบหนังสือ |
| Deny | บล็อกการลบถ้ามีวัตถุที่เกี่ยวข้องอยู่ | ป้องกันการลบหมวดหมู่ที่มีสินค้า |
การเลือก Delete Rule มีความสำคัญต่อความสมบูรณ์ของข้อมูล: Cascade โดยไม่ตรวจสอบอาจลบหนึ่งในสามของฐานข้อมูล ในขณะที่ Deny อาจบล็อกการดำเนินการด้วยข้อผิดพลาดที่ไม่ชัดเจน ในโค้ดการผลิต แนะนำให้ใช้ Nullify กับการจัดการระเบียนกำพร้าด้วยตนเอง
ในตัวแก้ไขโมเดล Xcode นักพัฒนาสามารถกำหนดไม่เพียงแค่ Entity และคุณลักษณะเท่านั้น แต่ยังรวมถึง constraints (ข้อจำกัดความเป็นเอกลักษณ์), ดัชนีเพื่อเร่งการค้นหา และค่าเริ่มต้นสำหรับคุณลักษณะ การเปลี่ยนแปลงโมเดลทั้งหมดจะถูกคอมไพล์เป็นไฟล์ .momd ซึ่งจะโหลดระหว่างการเริ่มต้น NSPersistentContainer การกำหนดเวอร์ชันโมเดล (Model Versioning) ช่วยให้รักษาสคีมาหลายเวอร์ชันและทำการโยกย้ายระหว่างกัน
NSPersistentContainer เป็นวัตถุเดียวที่จัดการสแต็ก Core Data ตั้งแต่ iOS 10 และ macOS 10.12 โดยห่อหุ้ม NSManagedObjectModel, NSPersistentStoreCoordinator และ NSManagedObjectContext ทำให้การโหลดโมเดลและการกำหนดค่าที่เก็บเป็นอัตโนมัติ สำหรับเวอร์ชันเก่ากว่า สแต็กถูกสร้างขึ้นด้วยตนเอง แต่ตอนนี้ไม่แนะนำอีกต่อไป
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
if let error { fatalError("Core Data load failed: \(error)") }
}
let context = container.viewContext
viewContext เป็นคอนเทกซ์หลักที่ผูกกับเธรดหลัก การอ่านและการอัปเดต UI ทั้งหมดจะดำเนินการผ่านมัน สำหรับประสิทธิภาพ แนะนำให้เขียนข้อมูลในคอนเทกซ์ลูกพื้นหลังที่มีการซิงโครไนซ์ภายหลัง
ตัวประสานงาน NSPersistentStoreCoordinator เชื่อมต่อโมเดลกับที่เก็บทางกายภาพบนดิสก์ Core Data รองรับที่เก็บหลายประเภท: SQLite (แนะนำ), Binary และ In-Memory ที่เก็บ SQLite รองรับการโยกย้าย การสำรองข้อมูลแบบเพิ่มหน่วย และความทนทานต่อความล้มเหลวระหว่างการเขียน
NSFetchRequest เป็นวัตถุที่อธิบายคำค้นหาถึงที่เก็บ Core Data ประกอบด้วยชื่อ Entity, ภาคแสดงการกรอง, ตัวอธิบายการเรียงลำดับและการตั้งค่าการดึงข้อมูล คำค้นหาจะถูกดำเนินการผ่าน context.fetch() ซึ่งส่งกลับอาร์เรย์ของ NSManagedObject
let request = NSFetchRequest<User>(entityName: "User")
request.predicate = NSPredicate(format: "age >= %d", 18)
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
request.fetchLimit = 50
let results = try context.fetch(request)
NSPredicate รองรับเงื่อนไขที่ซับซ้อน: LIKE, IN, BETWEEN, CONTAINS[c] (ไม่คำนึงถึงตัวพิมพ์ใหญ่-เล็ก), SUBQUERY สำหรับคำค้นหาที่ซ้อนกันบน Entity ที่เกี่ยวข้อง Core Data ยังรองรับ NSFetchedResultsController — คลาสสำหรับการโหลดข้อมูลแบบปฏิกิริยาใน UITableView ซึ่งติดตามการเปลี่ยนแปลงโดยอัตโนมัติและอัปเดตตารางด้วยส่วนแบบเคลื่อนไหว
การทำงานกับ Core Data ในแอปพลิเคชันแบบหลายเธรดต้องปฏิบัติตามกฎอย่างเคร่งครัด: NSManagedObject ไม่สามารถส่งตรงระหว่างเธรดได้ แต่ละเธรด (หรือคิว) ต้องใช้คอนเทกซ์ของตนเอง แนวทางหลักคือการสร้าง NSManagedObjectContext ลูกที่มีคิวส่วนตัว (NSPrivateQueueConcurrencyType) สำหรับการเขียนและ viewContext สำหรับการอ่าน
คอนเทกซ์ลูกบันทึกไปยังคอนเทกซ์แม่ จากนั้นคอนเทกซ์แม่บันทึกไปยังที่เก็บดิสก์ ซึ่งรับประกันว่าการเปลี่ยนแปลงจะไม่บล็อกเธรดหลัก และ UI จะเห็นสถานะที่สอดคล้องกันเสมอผ่าน mergeChanges หรือการอัปเดต viewContext อัตโนมัติเมื่อบันทึก
Core Data ใช้ faulting — กลไกการโหลดแบบหน่วงเวลาสำหรับวัตถุที่เกี่ยวข้อง เมื่อดึงข้อมูล User โดยไม่ขอที่อยู่ วัตถุ Address ที่เกี่ยวข้องจะไม่ถูกโหลดจนกว่าจะเข้าถึงผ่านสัญกรณ์จุด Faulting ประหยัดหน่วยความจำและเพิ่มความเร็วในการโหลด แต่อาจทำให้เกิดการเข้าถึงดิสก์ที่ไม่คาดคิดบนเธรดหลักหากไม่ควบคุมการเข้าถึงในคอนเทกซ์พื้นหลัง
สำหรับการทำงานแบบหลายเธรดอย่างมีประสิทธิภาพ ให้ใช้ NSBatchInsertRequest และ NSBatchDeleteRequest สำหรับการแทรกและลบเป็นกลุ่มโดยไม่โหลดวัตถุในหน่วยความจำ — ซึ่งสำคัญสำหรับการซิงโครไนซ์ข้อมูลกับเซิร์ฟเวอร์
การดำเนินการแบบกลุ่มจะดำเนินการโดยตรงที่ระดับ NSPersistentStoreCoordinator โดยข้ามคอนเทกซ์และกราฟวัตถุ ทำให้สามารถแทรก 10,000 ระเบียนในเวลาไม่กี่มิลลิวินาทีโดยไม่สร้างอินสแตนซ์ NSManagedObject 10,000 ตัวในหน่วยความจำ หลังจากดำเนินการคำขอแบบกลุ่มแล้ว คอนเทกซ์ต้องได้รับการอัปเดตผ่าน mergeChangesFromContextDidSaveNotification เพื่อให้ UI สะท้อนข้อมูลใหม่ Apple แนะนำการดำเนินการแบบกลุ่มสำหรับการโหลดข้อมูลเริ่มต้นและการซิงโครไนซ์กับเซิร์ฟเวอร์ในเวลากลางคืน
สำหรับการติดตามการเปลี่ยนแปลงใน Core Data ใช้ NSPersistentHistoryTracking — กลไกที่บันทึกแต่ละธุรกรรม (แทรก, อัปเดต, ลบ) ในประวัติแยกต่างหาก การเปิดใช้งานการติดตามประวัติช่วยให้ซิงโครไนซ์ข้อมูลระหว่างกระบวนการและแอปพลิเคชันต่างๆ ที่ทำงานกับไฟล์ SQLite เดียวกัน เช่น ระหว่างแอปพลิเคชันหลักและ Notification Service Extension การเปิดใช้งานทำผ่าน NSPersistentStoreDescription ด้วยแฟล็ก persistentHistoryTrackingKey และการอ่านผ่าน NSPersistentHistoryChangeRequest ด้วยการกรองตามวันที่และชนิดธุรกรรม
สำหรับการดีบักและการทำโปรไฟล์ประสิทธิภาพของ Core Data ใช้เครื่องมือ Core Data Profiler จากชุด Instruments ใน Xcode บน macOS ซึ่งแสดงการดำเนินการดึงข้อมูล แทรก ลบ และบันทึกทั้งหมดพร้อมระยะเวลาของแต่ละการดำเนินการและจำนวนวัตถุที่โหลดในตารางและกราฟไทม์ไลน์ นักพัฒนาสามารถระบุพื้นที่ที่มีปัญหา: การดึงข้อมูลเดียวกันหลายครั้ง (ขาดแคช), การรั่วไหลของวัตถุ fault เมื่อเลื่อนตาราง หรือการบล็อกเธรดหลักเนื่องจากการโหลดเอนทิตีที่เกี่ยวข้องแบบซิงโครนัส แนะนำให้เรียกใช้การทำโปรไฟล์บนอุปกรณ์จริง ไม่ใช่บนซิมูเลเตอร์ เนื่องจากประสิทธิภาพของซิมูเลเตอร์ไม่สะท้อนพฤติกรรมจริงของแอปพลิเคชันบน iPhone หรือ iPad
คำถามที่พบบ่อย
Core Data ไม่ใช่ฐานข้อมูล แต่เป็นชั้นการจัดการวัตถุที่สามารถใช้ SQLite เป็นที่เก็บ ซึ่งแตกต่างจาก SQLite โดยตรง Core Data ติดตามการเปลี่ยนแปลงของวัตถุ จัดการการเลิกทำ และมีกราฟวัตถุพร้อม faulting และแคช SQLite ให้การควบคุมคำค้นหามากกว่า แต่ต้องการเขียน SQL และจัดการธุรกรรมด้วยตนเอง
Core Data รองรับการโยกย้ายแบบเบา (Lightweight Migration) สำหรับการเปลี่ยนแปลงที่ไม่ทำลาย: เพิ่มคุณลักษณะ เปลี่ยนชื่อ ตั้งค่าเริ่มต้น สำหรับการเปลี่ยนแปลงที่ซับซ้อน จะสร้าง Mapping Model การโยกย้ายแบบเบาเปิดใช้งานด้วยแฟล็ก shouldMigrateAutomatically ใน NSPersistentStoreDescription
ได้ Core Data ผสานรวมกับ SwiftUI ผ่าน wrapper @FetchRequest สำหรับคำค้นหาและ @ObservedObject สำหรับการติดตามการเปลี่ยนแปลง SwiftUI จะอัปเดต View โดยอัตโนมัติเมื่อ ManagedObject เปลี่ยนแปลง ทำให้ Core Data และ SwiftUI เป็นสแต็กที่เข้ากันได้สำหรับการจัดการสถานะ
Fault คือตัวยึดตำแหน่งแบบเบาในกราฟ Core Data ที่ไม่มีข้อมูลของวัตถุที่เกี่ยวข้อง เมื่อตั้งค่า fault (ผ่าน refreshObject:) ข้อมูลจะถูกยกเลิกการโหลดจากหน่วยความจำ เมื่อเข้าถึงคุณสมบัติ fault จะเติมข้อมูลจากที่เก็บโดยอัตโนมัติ — นี่คือกลไกการโหลดแบบหน่วงเวลาที่ปรับการใช้หน่วยความจำให้เหมาะสม
สำหรับการทดสอบ ให้ใช้ชนิดที่เก็บ In-Memory: NSPersistentStoreDescription กับ NSInMemoryStoreType คอนเทนเนอร์ถูกสร้างด้วยโมเดลจากบันเดิลทดสอบ หลังจากแต่ละการทดสอบ ให้ลบวัตถุทั้งหมดหรือสร้างคอนเทนเนอร์ใหม่ — ซึ่งรับประกันการแยกกรณีทดสอบออกจากกัน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ