I'm facing an issue with accessing the result from a perform block in Core Data when fetching countries from the database in a background context. Here's the code snippet:
actor Repository {
@available(iOS 15.0, *)
private func fetchAllCountries() async -> [MCCountry]? {
let request = getFetchRequest()
let backgroundContext = container.newBackgroundContext()
do {
let result = try await backgroundContext.perform {
let countries = try backgroundContext.fetch(request) as? [MCCountry]
let attributeValue = countries?.first?.countryCode
debugPrint("Country code \(String(describing: attributeValue))") // returns value
return countries
}
debugPrint("Country \(String(describing: result))") // crashes here
return result
} catch {
debugPrint("error \(error)")
return nil
}
}
}
Caller:
Task {
await repository.fetchCountries { result in
if let result {
for value in result {
debugPrint("Value is \(String(describing: value.countryCode))") //returns nil
}
}
}
}
The problem is that even though I can access the result inside the perform block, the returned result from backgroundContext.perform seems to be inaccessible. When I try to access the result after the block, I encounter an EXC_BAD_ACCESS error. I expected to receive the result from the perform method and return it immediately in the fetchAllCountries method.
Am I missing something in my understanding? Shouldn't I expect a result from the perform block? Can someone please help me identify what's wrong with the code?
Thank you in advance.
The backgroundContext you are fetching on is being deallocated after your function executes. And then all the objects fetched on it will not be valid anymore.
If the purpose of the fetch is to display data, then it must occur on the viewContext.
If you have a large query to preprocess your data, you could return ObjectIDs instead of objects in your async fetch and then create a predicate to fetch objects contained in objectIDs with those on the viewContext to actually get the objects to display.