Как выполнить Core Data NSFetchRequest в методе класса?

У меня есть файл AppName.xcdatamodeld с Category в Entities. В Category я успешно добавляю записи из SwiftUI и успешно извлекаю их в View вот так:

import SwiftUI
import CoreData

struct CategoriesList: View {
    @Environment(\.managedObjectContext) var moc
    
    var fetchRequest: FetchRequest<CountdownCategory>
    var countdownCategories: FetchedResults<CountdownCategory> {
        fetchRequest.wrappedValue
    }
    
    var body: some View {
        ForEach(countdownCategories, id: \.self) { countdownCategory in
            Text(countdownCategory.title ?? "Category")
        }
    }
    
    init() {
        fetchRequest = FetchRequest<CountdownCategory>(entity: CountdownCategory.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \CountdownCategory.dateAdded, ascending: false)])
    }
}

Теперь мне нужно выполнить тот же запрос в другом месте программы - не в представлении SwiftUI, а в методе класса:

import Foundation
import CoreData

class Categories {
    func getCategories() {
        let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        let categoriesFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "CountdownCategory")
         
        do {
            let categoriesFetch = try moc.fetch(categoriesFetch) as! [CountdownCategory]
        } catch {
            fatalError("Failed to fetch categories: \(error)")
        }
        
        // etc.
    }
}

Я нашел пример кода в официальной документации Core Data, однако, когда я пытаюсь выполнить это, я получаю сообщение об ошибке:

*** Завершение работы приложения из-за необработанного исключения «NSInvalidArgumentException», причина: «+entityForName: nil не является допустимым NSPersistentStoreCoordinator для поиска имени объекта «CountdownCategory»

Буду признателен за любую помощь в исправлении этой ошибки. Моя цель — получить данные из Core Data от CountdownCategory этим методом. (Свифт 5.2)

UPD №1: при использовании let categoriesFetch = CountdownCategory.fetchRequest() получаю ошибку:

Неоднозначное использование 'fetchRequest()'

UPD №2: при использовании let categoriesFetch: NSFetchRequest<CountdownCategory> = CountdownCategory.fetchRequest() у меня не вылетает. Но как мне получить данные?


person Igor R.    schedule 26.06.2020    source источник


Ответы (1)


let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

Здесь вы создаете совершенно новый контекст управляемого объекта без поддержки постоянного хранилища или модели. Это неправильный способ сделать это. Вам нужно использовать тот же контекст, который вы передали объекту среды SwiftUI, откуда бы он ни исходил.

Вы сказали, что у делегата приложения есть NSPersistentContainer, поэтому я предполагаю, что вы использовали шаблон приложения SwiftUI/Core Data. В этом случае вам нужно заменить строку кода выше (let moc = ...) на что-то вроде этого:

let moc = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

Если вы используете шаблон, вы можете заглянуть в SceneDelegate.swift и посмотреть, где контекст внедряется в среду SwiftUI с помощью аналогичного кода.

person jrturton    schedule 26.06.2020
comment
Я передаю объект среды в View следующим образом: CategoriesList().environment(\.managedObjectContext, moc), но я изо всех сил пытаюсь объявить его/использовать его в методе. - person Igor R.; 26.06.2020
comment
откуда moc в коде вашего комментария? Это экземпляр, который вам нужно использовать в методе класса - person jrturton; 26.06.2020
comment
Это происходит от @Environment(\.managedObjectContext) var moc в представлении до var body: some View {... - person Igor R.; 26.06.2020
comment
вам нужно следить за этим вверх по цепочке, пока вы не найдете, где он создается в первую очередь. В вашем приложении есть NSPersistentContainer где-нибудь? - person jrturton; 26.06.2020
comment
Да, в AppDelegate.swift в разделе Core Data Stack, let container = NSPersistentCloudKitContainer(name: "MyTitle") - person Igor R.; 26.06.2020