ماندگاری (Core Data) (Persistence (Core Data))
اینجا «ماندگاری با Core Data» را یاد می گیری. «Core Data» چارچوب ماندگاری شی گراست. داده ها و رابطه ها را مدیریت می کند. سپس تغییرات را دنبال می کند. گاهی زیرساخت از SQLite استفاده می کند. این یعنی ذخیره سازی مطمئن و مقیاس پذیر.
Core Data چیست؟
«Core Data» چارچوب شی گرا برای مدل، ذخیره و کوئری است. بنابراین مدل ها و رابطه ها سامان می گیرند. سپس تغییرات رصد می شوند. اغلب پشت صحنه SQLite قرار دارد.
راه اندازی پایه با NSPersistentContainer
می توانی از هنگام ساخت پروژه، Core Data را فعال کنی. یا یک «NSPersistentContainer» بسازی. سپس «viewContext» را به SwiftUI بدهی با «.environment(\.managedObjectContext)».
import SwiftUI
import CoreData
@objc(Note)
class Note: NSManagedObject {
@NSManaged var title: String?
}
extension Note {
@nonobjc
class func fetchRequest() -> NSFetchRequest<Note> {
return NSFetchRequest<Note>(entityName: "Note")
}
}
struct PersistenceController {
static let shared: PersistenceController = PersistenceController()
let container: NSPersistentContainer
init() {
let model: NSManagedObjectModel = NSManagedObjectModel()
let entity: NSEntityDescription = NSEntityDescription()
entity.name = "Note"
entity.managedObjectClassName = NSStringFromClass(Note.self)
let title: NSAttributeDescription = NSAttributeDescription()
title.name = "title"
title.attributeType = .stringAttributeType
title.isOptional = true
entity.properties = [title]
model.entities = [entity]
container = NSPersistentContainer(name: "MyModel", managedObjectModel: model)
let description: NSPersistentStoreDescription = NSPersistentStoreDescription()
description.type = NSInMemoryStoreType
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { _, error in
if let error {
fatalError("Unresolved error: \(error)")
}
}
}
}
struct BasicCoreDataView: View {
@Environment(\.managedObjectContext) private var context: NSManagedObjectContext
@FetchRequest(sortDescriptors: []) private var items: FetchedResults<Note>
var body: some View {
List(items, id: \.objectID) { note in
Text(note.title ?? "")
}
.toolbar {
Button("Add") {
add()
}
}
}
private func add() {
let i: Note = Note(context: context)
i.title = "New"
try? context.save()
}
}
import SwiftUI
struct ContentView: View {
var body: some View {
BasicCoreDataView()
}
}
import SwiftUI
import CoreData
@main
struct MyApp: App {
let persistence: PersistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistence.container.viewContext)
}
}
}
جمع بندی راه اندازی
- Container را بساز و بارگذاری کن.
- Context را به محیط View بده.
- با FetchRequest لیست را پر کن.
نکته: اگر مدل زیاد است، فایل «.xcdatamodeld» بساز. سپس موجودیت ها را آنجا تعریف کن.
نمونه Notes با FetchRequest
اکنون یک View ساده می سازیم. سپس با «FetchRequest» یادداشت ها را می خوانیم. این کار الگوی اصلی بسیاری از اپ هاست.
import SwiftUI
import CoreData
class NoteEntity: NSManagedObject {
@NSManaged public var id: UUID?
@NSManaged public var title: String?
@NSManaged public var body: String?
}
extension NoteEntity: Identifiable {}
struct PersistenceController {
static let shared: PersistenceController = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "MyModel")
container.loadPersistentStores { _, error in
if let error {
fatalError("Unresolved error: \(error)")
}
}
}
}
struct NotesCoreDataView: View {
@Environment(\.managedObjectContext) private var context: NSManagedObjectContext
@FetchRequest(
sortDescriptors: [
NSSortDescriptor(keyPath: \NoteEntity.title, ascending: true)
]
)
private var notes: FetchedResults<NoteEntity>
var body: some View {
List(notes) { n in
VStack(alignment: .leading) {
Text(n.title ?? "Untitled").font(.headline)
Text(n.body ?? "").font(.subheadline)
}
}
.toolbar {
Button("Add") {
add()
}
}
}
private func add() {
let n: NoteEntity = NoteEntity(context: context)
n.id = UUID()
n.title = "New Note"
n.body = ""
try? context.save()
}
}
import SwiftUI
struct ContentView: View {
var body: some View {
NotesCoreDataView()
}
}
import SwiftUI
import CoreData
@main
struct MyApp: App {
let persistence: PersistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistence.container.viewContext)
}
}
}
اشتراک Store با App Group
می توانی فایل SQLite را در App Group بگذاری. سپس ویجت همان داده را می خواند. بنابراین تجربه یکپارچه می گیری.
import SwiftUI
import CoreData
struct PersistenceController {
static let shared: PersistenceController = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "MyModel")
if let groupURL: URL = FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: "group.com.example.notes"
) {
let storeURL: URL = groupURL.appendingPathComponent("MyModel.sqlite")
let description: NSPersistentStoreDescription = NSPersistentStoreDescription(url: storeURL)
container.persistentStoreDescriptions = [description]
}
container.loadPersistentStores { _, error in
if let error {
fatalError("Unresolved error: \(error)")
}
}
}
}
struct AppGroupListView: View {
@Environment(\.managedObjectContext) private var context: NSManagedObjectContext
@FetchRequest(sortDescriptors: []) private var items: FetchedResults<Item>
var body: some View {
List(items) { item in
Text(item.title ?? "")
}
.toolbar {
Button("Add") {
add()
}
}
}
private func add() {
let i: Item = Item(context: context)
i.title = "Shared Item"
try? context.save()
}
}
import SwiftUI
struct ContentView: View {
var body: some View {
AppGroupListView()
}
}
import SwiftUI
import CoreData
@main
struct MyApp: App {
let persistence: PersistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistence.container.viewContext)
}
}
}
نکته: کارهای سنگین را از «viewContext» دور نگه دار. برای ایمپورت از کانتکست پس زمینه استفاده کن.
جمع بندی سریع
- Container را بساز و Context را تزریق کن.
- با FetchRequest داده ها را بخوان.
- ذخیره سازی می تواند مشترک باشد.
- پس زمینه برای کار سنگین بهتر است.
ادامه مسیر: UserDefaults برای تنظیمات سبک. سپس الگوی MVVM برای جداسازی بهتر. همچنین ماندگاری با Core Data را به عنوان مرجع نگه دار.