Swift 在后台线程中使用NSManagedObjectContext时出错

Swift 在后台线程中使用NSManagedObjectContext时出错,swift,core-data,Swift,Core Data,所以,当我保存到核心数据时,我一直会遇到这个错误 Coredata[21468:13173906][error]错误:SQLCore dispatchRequest:异常处理请求:,**-\u referenceData64仅为抽象类定义。定义-[NSTemporaryObjectID\u默认值\u referenceData64]!用户信息为(空) 我最近完成了一门关于核心数据的课程,讲师谈到了核心数据不是线程安全的。所以他建议的是一个孩子/家长的环境,这就是我试图做的,但不断从上面得到错误。

所以,当我保存到核心数据时,我一直会遇到这个错误

Coredata[21468:13173906][error]错误:SQLCore dispatchRequest:异常处理请求:,**-\u referenceData64仅为抽象类定义。定义-[NSTemporaryObjectID\u默认值\u referenceData64]!用户信息为(空)

我最近完成了一门关于核心数据的课程,讲师谈到了核心数据不是线程安全的。所以他建议的是一个孩子/家长的环境,这就是我试图做的,但不断从上面得到错误。这就是我的代码的外观

struct Service {
static let shared = Service()

func downloadPokemonsFromServer(completion: @escaping ()->()) {
    let urlString = "https://pokeapi.co/api/v2/pokemon?limit=9"
    guard let url = URL(string: urlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let err = error {
            print("Unable to fetch pokemon", err)
        }

        guard let data = data else { return }
        let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        privateContext.parent = CoreDataManager.shared.persistentContainer.viewContext

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        do {
            let pokemonJSON = try decoder.decode(PokemonsJSON.self, from: data)
            pokemonJSON.pokemons.forEach { (JSONPokemon) in
                //Works fine with privateContext here
               let pokemon = Pokemon(context: privateContext)
                pokemon.name = JSONPokemon.name
                pokemon.url = JSONPokemon.detailUrl
            }

            //Why does the privateContext work here
            //and doesn't crash my app.
            try privateContext.save()
            try privateContext.parent?.save()
            completion()
        } catch let err {
            print("Unable to decode PokemonJSON. Error: ",err)
            completion()
        }
    }.resume()
}

func fetchMoreDetails(pokemon: Pokemon, urlString: String, context: NSManagedObjectContext, completion: @escaping ()->()) {
    guard let url = URL(string: urlString) else { return }
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let err = error {
            print("Unable to get more details for pokemon", err)
        }

        guard let data = data else { return }
        let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        privateContext.parent = CoreDataManager.shared.persistentContainer.viewContext

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        do {
            let pokemonDetailJSON = try decoder.decode(PokemonDetailJSON.self, from: data)
            pokemonDetailJSON.types.forEach { (nestedType) in
                // I can just change this to context and it works
                // Why doesnt it work with privateContext and crashes my app

                let type = Type(context: privateContext)
                type.name = nestedType.type.name

                pokemon.addToTypes(type)
            }

            try privateContext.save()
            try privateContext.parent?.save()

            completion()
        } catch let err {
            print("Unable to decode pokemon more details", err)
            completion()
        }

    }.resume()
}
}
因此,在下载的PokemonsFromSever中,我调用了一个api来解析json并将其保存到Coredata中。我按照讲师的指示,创建一个privateContext,然后将其父对象设置为我的主上下文。然后我创建了一个新的口袋妖怪,它使用我的privateContext而不是我的mainContext有一个名称和url。当我完全解析我的口袋妖怪时,我进入了另一个api,它有关于该口袋妖怪的更多细节

这就是我的应用程序开始崩溃的地方。从fetchMoreDetails中可以看到,有一个参数是上下文。当我尝试使用privateContext创建新类型时,它会使我的应用程序崩溃。当我使用通过它传递的上下文时,它工作得很好。我想知道为什么privateContext在downloadPokemonFromServer中工作,而不是在fetchMoreDetails中工作。我在上面留下了一条评论,我认为这会使我的应用程序崩溃。这就是我在ViewController中使用此操作调用它的方式

@objc func handleRefresh() {

    Service.shared.downloadPokemonsFromServer {
        let context = CoreDataManager.shared.persistentContainer.viewContext
        self.pokemonController.fetchedObjects?.forEach({ (pokemon) in

            Service.shared.fetchMoreDetails(pokemon: pokemon, urlString: pokemon.url ?? "", context: context) {

            }
        })
    }
    tableView.refreshControl?.endRefreshing()
}