Search code examples
swiftcore-dataclosures

Alternatives to changing signature of a closure passed as parameter


It's easier to show an example than trying to explain it, will use CoreData as context:

Given NSManagedObjectContext's perform() function (removed unnecessary parts of the signature)

extension NSManagedObjectContext {
    public func perform<T>(_ block: @escaping () throws -> T) async rethrows -> T
} 

I want to write a wrapper for MOC that calls such function, for example.

class Persistence {
    func read<T>(_ block: @escaping (NSManagedObjectContext) throws -> T) async rethrows -> T { // 1.
        return try await container.viewContext.perform(block) // 2.
    }
}

So that i can use it such as:

try await persistence.read { moc in
    let repo = Repository(context: moc)
    ...
}

Now the problem is that given the closure signature required by perform () throws -> T (see // 1.) i can't obviously pass a closure of type (NSManagedObjectContext) throws -> T (see // 2.).

Question: Is there a pattern that would allow me to do such a thing in Swift? Or a concurrency safe alternative to perform?


Solution

  • If I understand you correctly this should work

    func read<T>(_ block: @escaping (NSManagedObjectContext) throws -> T) async rethrows -> T {
        let moc = container.viewContext // or some background context
        return try await moc.perform { try block(moc) } // 2.
    }