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