Core Data คือเฟรมเวิร์กของ Apple สำหรับจัดการกราฟวัตถุในแอปพลิเคชัน iOS และ macOS โดยให้การคงอยู่ของข้อมูล การติดตามการเปลี่ยนแปลง การยกเลิกการดำเนินการ และการรวมเข้ากับ UI ผ่าน 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 โดยตรงและไม่ใช่ DBMS 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 ทำให้ความแตกต่างระหว่างประเภทพื้นที่จัดเก็บเป็นนามธรรมผ่าน API บริบทแบบรวม
NSManagedObject คือคลาสพื้นฐานสำหรับวัตถุ Core Data ทั้งหมด แทนเรกคอร์ดเอนทิตีเดียว วัตถุที่มีการจัดการแต่ละรายการมี NSManagedObjectID เฉพาะ (ตัวระบุถาวร) เชื่อมโยงกับบริบท และติดตามการเปลี่ยนแปลงผ่าน KVO (Key-Value Observing) นักพัฒนาสร้างคลาสย่อยของ NSManagedObject เพื่อกำหนดคุณสมบัติเอนทิตีที่ระบุชนิด
NSManagedObjectContext คือส่วนประกอบกลางของ Core Data ที่ให้พื้นที่ทำงานสำหรับการดำเนินการกับวัตถุทั้งหมด บริบทติดตามการเพิ่ม การลบ และการเปลี่ยนแปลง (การติดตามการเปลี่ยนแปลง) รองรับการยกเลิกการดำเนินการผ่าน undoManager และรวมการเปลี่ยนแปลงจากบริบทอื่นโดยอัตโนมัติเมื่อได้รับการแจ้งเตือนการบันทึก
กฎคิวส่วนตัว: NSManagedObjectContext ถูกสร้างด้วย .privateQueueConcurrencyType หรือ .mainQueueConcurrencyType บริบทหลักเชื่อมโยงกับเธรด UI หลัก ในขณะที่บริบทส่วนตัวทำงานบนคิวพื้นหลัง แต่ละบริบทต้องใช้เฉพาะบนคิวของตัวเองเท่านั้น — การเข้าถึงวัตถุที่มีการจัดการจากเธรดอื่นทำให้เกิดการขัดข้อง 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 รับการเปลี่ยนแปลงจากบริบทพื้นหลังโดยอัตโนมัติเมื่อบันทึก อัปเดต UI โดยไม่ต้องดึงข้อมูลอีกครั้งด้วยตนเอง
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 ที่มีการบันทึกของตัวเอง และสำหรับ UI ให้ใช้ viewContext ที่มีการบันทึกอัตโนมัติตามเวลาหรือเมื่อแอปเข้าสู่พื้นหลัง
แนวปฏิบัติแรก — ใช้ NSPersistentCloudKitContainer เพื่อซิงค์ข้อมูลระหว่างอุปกรณ์ของผู้ใช้ผ่าน iCloud การซิงค์คลาวด์เปิดใช้งานโดยการเพิ่มตัวเลือก CloudKit ไปยังคำอธิบายพื้นที่จัดเก็บถาวร Core Data จัดการข้อขัดแย้งในการซิงค์โดยอัตโนมัติและรวมการเปลี่ยนแปลงจากอุปกรณ์อื่น
แนวปฏิบัติที่สอง — หลีกเลี่ยง fetchRequest โดยไม่มีภาคแสดงบนตารางขนาดใหญ่ การดึงข้อมูลโดยไม่มีเงื่อนไขแต่ละครั้งจะโหลดวัตถุเอนทิตีทั้งหมดลงในหน่วยความจำ ทำให้มีการใช้ RAM สูงและ UI ทำงานช้า ใช้ภาคแสดงและขีดจำกัดเสมอ สำหรับการแบ่งหน้า ให้ใช้ 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 คือเฟรมเวิร์กการจัดการกราฟวัตถุ มันให้ API สำหรับทำงานกับวัตถุ ติดตามการเปลี่ยนแปลง และคงอยู่ ฐานข้อมูลภายใต้ฝาครอบของ Core Data (SQLite โดยดีฟอลต์) ไม่ควรสับสนกับเฟรมเวิร์กเอง Core Data คือ ORM ไม่ใช่ DBMS
ได้ 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 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม