I'm implementing a helper method for CoreData
public func doInMain(_ block: (NSManagedObjectContext) -> Void) {
guard let context = mainQueueContext else { return }
context.performAndWait({
block(context)
})
}
It works well and can be called like this:
CoreDataManager().doInMain { moc in
// do your fetch request with managed object context
}
But it's very annoying when I want to try an error in doInMain
block, because it can't be rethrowed by the calling function. Since the bloc is nonescaping
, it should be done.
So I added:
public func doInMain(_ block: (NSManagedObjectContext) throws -> Void) rethrows {
guard let context = mainQueueContext else { return }
context.performAndWait({
try block(context)
})
}
But NSManagedObjectContext.performAndWait do not rethrows errors, so it won't compile.
It tryed this:
public func doInMain(_ block: (NSManagedObjectContext) throws -> Void) rethrows {
guard let context = mainQueueContext else { return }
var thrownError: Error?
context.performAndWait({
do { try block(context) }
catch { thrownError = error }
})
if let error = thrownError {
throw error
}
}
But now the compiler says A function declared 'rethrows' may only throw if its parameter does
Am I screwed up? Is there a workaround?
Thanks
Not entirely ideal, but one option would be to just write two overloads – one that takes a closure that doesn't throw and itself doesn't throw, and another that takes a throwing closure and itself throws.
For example:
public func doInMain(_ block: (NSManagedObjectContext) -> Void) {
guard let context = mainQueueContext else { return }
context.performAndWait {
block(context)
}
}
public func doInMain(_ block: (NSManagedObjectContext) throws -> Void) throws {
guard let context = mainQueueContext else { return }
var thrownError: Error?
context.performAndWait {
do {
try block(context)
} catch {
thrownError = error
}
}
if let error = thrownError {
throw error
}
}
Bear in mind that if desired, you could always implement the non-throwing overload in terms of the throwing overload:
public func doInMain(_ block: (NSManagedObjectContext) -> Void) {
let fn = doInMain as ((NSManagedObjectContext) throws -> Void) throws -> Void
try! fn(block)
}
You should be able to use both overloads in much the same way as a single rethrowing overload.