Bagaimana cara menjalankan Core Data NSFetchRequest dalam metode kelas?

Saya memiliki file AppName.xcdatamodeld, dengan Category di Entities. Di Category saya berhasil menambahkan catatan dari SwiftUI dan berhasil mengambilnya di View seperti:

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)])
    }
}

Sekarang saya perlu menjalankan kueri yang sama di tempat berbeda dalam suatu program - bukan dalam tampilan SwiftUI, tetapi dalam metode di kelas:

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.
    }
}

Saya mencari kode contoh di dokumentasi Data Inti resmi, namun ketika saya mencoba menjalankan ini saya mendapatkan kesalahan:

*** Menghentikan aplikasi karena pengecualian 'NSInvalidArgumentException' yang tidak tertangkap, alasan: '+entityForName: nil bukan NSPersistentStoreCoordinator yang sah untuk mencari nama entitas 'CountdownCategory''

Akan sangat menghargai bantuan apa pun untuk memperbaiki kesalahan itu. Tujuan saya adalah mendapatkan data dari Data Inti dari CountdownCategory dalam metode ini. (Cepat 5.2)

UPD #1: ketika saya menggunakan let categoriesFetch = CountdownCategory.fetchRequest() saya mendapatkan kesalahan:

Penggunaan 'fetchRequest()' yang ambigu

UPD #2: ketika saya menggunakan let categoriesFetch: NSFetchRequest<CountdownCategory> = CountdownCategory.fetchRequest() saya tidak mengalami crash. Tapi bagaimana cara mendapatkan datanya?


person Igor R.    schedule 26.06.2020    source sumber


Jawaban (1)


let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

Anda membuat konteks objek terkelola yang baru di sini, tanpa penyimpanan atau model persisten yang mendukung. Itu bukan cara yang tepat untuk melakukannya. Anda perlu menggunakan konteks yang sama dengan yang Anda masukkan ke objek lingkungan SwiftUI, dari mana pun asalnya.

Anda telah mengatakan bahwa delegasi aplikasi memiliki NSPersistentContainer jadi saya kira Anda telah menggunakan templat aplikasi SwiftUI/Core Data. Dalam hal ini Anda perlu mengganti baris kode di atas (let moc = ...) dengan sesuatu seperti ini:

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

Jika Anda menggunakan templat, Anda dapat melihat di SceneDelegate.swift dan melihat di mana konteks dimasukkan ke dalam lingkungan SwiftUI menggunakan kode serupa.

person jrturton    schedule 26.06.2020
comment
Saya meneruskan objek lingkungan ke Tampilan seperti: CategoriesList().environment(\.managedObjectContext, moc), tetapi saya kesulitan mendeklarasikannya/menggunakannya dalam metode. - person Igor R.; 26.06.2020
comment
dari mana asal moc kode di komentar Anda? Itulah contoh yang perlu Anda gunakan dalam metode kelas - person jrturton; 26.06.2020
comment
Itu berasal dari @Environment(\.managedObjectContext) var moc dalam tampilan sebelum var body: some View {... - person Igor R.; 26.06.2020
comment
Anda perlu menindaklanjutinya sampai Anda menemukan di mana rantai itu dibuat. Apakah aplikasi Anda memiliki NSPersistentContainer di mana saja? - person jrturton; 26.06.2020
comment
Ya, di AppDelegate.swift di bagian Tumpukan Data Inti, let container = NSPersistentCloudKitContainer(name: "MyTitle") - person Igor R.; 26.06.2020