2

因此,当我保存到核心数据时,我不断收到此错误。

Coredata[21468:13173906] [error] 错误:SQLCore dispatchRequest:异常处理请求:,** -_referenceData64 仅为抽象类定义。定义 -[NSTemporaryObjectID_default _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()
}
}

所以在 downloadPokemonsFromSever 中,我调用了一个解析 json 并将其保存到 Coredata 的 api。我按照老师的指示创建了一个 privateContext,然后将其父级设置为我的 mainContext。然后我使用我的 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()
}
4

0 回答 0