Приведи пример основных операций (CRUD) с Core Data в iOS.

Ответ

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, а не магия. Удачи, и да не потонет твоя «Муму» в омуте багов!