I'm working on an App that still supports iOS 13 and need to fetch some data with CoreData.
This is how I would normally do it
context.perform({
let results = try context.fetch(request)
})
Now with Xcode 13 and async/await being available back to iOS 13 I get a compiler error
'perform(schedule:_:)' is only available in iOS 15.0 or newer
Jumping to definition shows the following new API in CoreData
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension NSManagedObjectContext {
public func performAndWait<T>(_ block: () throws -> T) rethrows -> T
public func perform<T>(schedule: NSManagedObjectContext.ScheduledTaskType = .immediate, _ block: @escaping () throws -> T) async rethrows -> T
}
When commenting out the code in the Block, it instead jumps to the old API in CoreData/NSManagedObjectContext
/* asynchronously performs the block on the context's queue. Encapsulates an autorelease pool and a call to processPendingChanges */
@available(iOS 5.0, *)
open func perform(_ block: @escaping () -> Void)
Why does the compiler select the new variant of perform
and how can I force it to use the older non-async version?
Edit: Here is a minimal sample project that demonstrates the issue: https://github.com/iv-mexx/CoreDataRepro
Thanks to @Cy-4AH I've figured it out!
The problem was, that I was doing everything, including the
context.perform
in one bigdo / catch
blockThe new extension method for
perform
is now marked asrethrows
whereas the old one was not, so the fact there was a throwing method in the perform block meant the compiler selected the rethrowingperform
which is only available on iOS >= 15.@Cy-4AH suggested to use
try?
instead oftry
which works because the error is caught right there, not forcing therethrowing
method to be used.Another solution is to move the
do/catch
inside theperform
: