Ответ
Core Data — это фреймворк для управления графом объектов (ORM) и сохранения их на диск. Ниже приведены примеры базовых операций CRUD (Create, Read, Update, Delete).
Предположим, есть сущность Person с атрибутами name (String) и age (Int16).
1. Настройка Core Data Stack (обычно в AppDelegate или отдельном классе)
import CoreData
class CoreDataStack {
static let shared = CoreDataStack()
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "YourDataModel")
container.loadPersistentStores { description, error in
if let error = error { fatalError("Unable to load store: (error)") }
}
return container
}()
var context: NSManagedObjectContext {
return persistentContainer.viewContext // Контекст главного потока
}
func saveContext() {
if context.hasChanges {
do {
try context.save()
} catch {
print("Save error: (error)")
}
}
}
}
2. Операции CRUD
C (Create) — Создание объекта
func createPerson(name: String, age: Int16) {
let context = CoreDataStack.shared.context
// Создаем новый управляемый объект в контексте.
let newPerson = Person(context: context)
newPerson.name = name
newPerson.age = age
// Сохраняем контекст, чтобы записать изменения в хранилище.
CoreDataStack.shared.saveContext()
}
R (Read) — Чтение (Fetch) объектов
func fetchAllPeople() -> [Person] {
let context = CoreDataStack.shared.context
// Создаем запрос (FetchRequest) для сущности Person.
let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
// Опционально: добавляем сортировку (NSSortDescriptor).
let sortByName = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortByName]
// Опционально: добавляем предикат для фильтрации (NSPredicate).
// fetchRequest.predicate = NSPredicate(format: "age > %@", NSNumber(value: 18))
do {
let people = try context.fetch(fetchRequest)
return people
} catch {
print("Fetch failed: (error)")
return []
}
}
U (Update) — Обновление объекта
func updatePerson(_ person: Person, newName: String) {
// Обновляем свойства существующего управляемого объекта.
person.name = newPersonName
// Сохраняем контекст.
CoreDataStack.shared.saveContext()
}
D (Delete) — Удаление объекта
func deletePerson(_ person: Person) {
let context = CoreDataStack.shared.context
// Удаляем объект из контекста.
context.delete(person)
// Сохраняем контекст.
CoreDataStack.shared.saveContext()
}
// Пример удаления всех объектов
func deleteAllPeople() {
let context = CoreDataStack.shared.context
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = Person.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try context.execute(deleteRequest) // Эффективно для массового удаления
try context.save()
} catch {
print("Batch delete error: (error)")
}
}
Важные best practices:
- Работа с
NSManagedObjectContextдолжна происходить в том потоке, в котором он был создан (viewContext— главный поток). - Для фоновых операций используйте
persistentContainer.newBackgroundContext(). - Всегда обрабатывайте ошибки при
save()иfetch(). - Используйте
NSFetchedResultsControllerдля эффективной привязки данных кUITableViewилиUICollectionView.
Ответ 18+ 🔞
А, Core Data, ёпта! Ну это ж классика, как Герасим с Муму, только с объектами и базой. Смотри, разжуем эту графоманию про ORM от Apple, чтобы ты не выебал мозг об стену на первых же запросах.
Вот тебе разбор полётов, как с этим чудом работать, чтобы не получилось «Муму» в итоге.
Сначала надо эту хрень инициализировать. Обычно делают какого-нибудь менеджера, чтобы не размазывать по всему коду. Смотри, как примерно:
import CoreData
class CoreDataStack {
static let shared = CoreDataStack()
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "YourDataModel")
container.loadPersistentStores { description, error in
if let error = error { fatalError("Unable to load store: (error)") }
}
return container
}()
var context: NSManagedObjectContext {
return persistentContainer.viewContext // Контекст главного потока
}
func saveContext() {
if context.hasChanges {
do {
try context.save()
} catch {
print("Save error: (error)")
}
}
}
}
Это типа наш фундамент, блядь. Без него — нихуя.
А теперь, собственно, вся магия с объектами. Допустим, у нас сущность Person с полями name и age. Начинаем шаманить.
C — Create. То есть, создать запись.
func createPerson(name: String, age: Int16) {
let context = CoreDataStack.shared.context
// Создаем новый управляемый объект в контексте.
let newPerson = Person(context: context)
newPerson.name = name
newPerson.age = age
// Сохраняем контекст, чтобы записать изменения в хранилище.
CoreDataStack.shared.saveContext()
}
Всё просто, как три копейки: взял контекст, родил объект, запихал данные, сохранил. Главное — не забыть saveContext(), а то будет как в том анекдоте: «всё сделал, но не кончил».
R — Read. Вытащить всё на свет божий.
func fetchAllPeople() -> [Person] {
let context = CoreDataStack.shared.context
// Создаем запрос (FetchRequest) для сущности Person.
let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
// Опционально: добавляем сортировку (NSSortDescriptor).
let sortByName = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortByName]
// Опционально: добавляем предикат для фильтрации (NSPredicate).
// fetchRequest.predicate = NSPredicate(format: "age > %@", NSNumber(value: 18))
do {
let people = try context.fetch(fetchRequest)
return people
} catch {
print("Fetch failed: (error)")
return []
}
}
Вот тут уже можно поизвращаться: отсортировать, отфильтровать — в общем, найти своих баранов в стаде. NSPredicate — это вообще отдельная песня, на нём можно целые поэмы писать.
U — Update. Обновить старую запись.
func updatePerson(_ person: Person, newName: String) {
// Обновляем свойства существующего управляемого объекта.
person.name = newPersonName
// Сохраняем контекст.
CoreDataStack.shared.saveContext()
}
Да тут вообще нихуя сложного: нашёл объект, поменял ему поле, сохранил. Главное — объект должен быть живой, из контекста, а не какой-нибудь сбоку припёковый.
D — Delete. Отправить на хуй.
func deletePerson(_ person: Person) {
let context = CoreDataStack.shared.context
// Удаляем объект из контекста.
context.delete(person)
// Сохраняем контекст.
CoreDataStack.shared.saveContext()
}
// Пример удаления всех объектов
func deleteAllPeople() {
let context = CoreDataStack.shared.context
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = Person.fetchRequest()
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try context.execute(deleteRequest) // Эффективно для массового удаления
try context.save()
} catch {
print("Batch delete error: (error)")
}
}
Удалить одного — context.delete(person). Устроить геноцид всех записей разом — NSBatchDeleteRequest. Осторожнее с последним, а то потом будешь как Герасим — «что же я, мудак, сделал?».
И напоследок, блядь, святая святых — best practices:
- Контекст
viewContext— только для главного потока! Полез в фоне — получишь пизды. Для фона естьpersistentContainer.newBackgroundContext(). - Ошибки при
save()иfetch()обрабатывай всегда. Не делай вид, что их нет, они вылезут в самый неподходящий момент, как геморрой. - Хочешь привязать данные к таблице и не ебать мозг обновлениями?
NSFetchedResultsController— твой друг, товарищ и брат. Хуй с горы, а не контроллер.
Вот и вся нехитрая наука. Главное — не перемудрить и помнить, что это всего лишь обёртка над SQLite, а не магия. Удачи, и да не потонет твоя «Муму» в омуте багов!