Ошибка при работе с NSManagedObjectContext в фоновом потоке - PullRequest
2 голосов
/ 09 февраля 2020

Поэтому я получаю эту ошибку, когда сохраняю данные ядра.

Coredata [21468: 13173906] [ошибка]: ошибка: SQLCore dispatchRequest: запрос обработки исключительной ситуации: ** определена только ** -_referenceData64 для абстрактного класса. Определить - [NSTevenObjectID_default _referenceData64]! с userInfo (ноль)

Я недавно закончил курс по основным данным, преподаватель немного по топи c говорит, что данные ядра не являются поточно-ориентированными. Итак, он предложил дочерний / родительский контекст, поэтому я пытался сделать это, но продолжал получать ошибку сверху. Вот как выглядит мой код.

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 я вызываю API, который анализирует json и сохраняет его в Coredata. Я следовал инструкциям моего инструктора, создавая privateContext и затем устанавливая его родителя в свой mainContext. Затем я создаю нового покемона с именем и URL-адресом, используя мой privateContext, а НЕ mainContext. Когда я полностью разбираю своего покемона I go в другой API, в котором есть более подробная информация об этом покемоне.

Вот где мое приложение начинает создавать sh. Как вы можете видеть из 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()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...