@objc public final class DismissHandler: NSObject {
public func dismissViewController(completion: (() -> Void)?) {
let bar = Bar()
bar?.doSomething(completionHandler: completion) // <- Passing non-sendable parameter 'completion' to function expecting a @Sendable closure
let zar = Zar()
zar.doSomething(completionHandler: completion) // <- No error here
}
}
When importing methods from Objective-C, the compiler understands something about how they're conventionally used, including that completion handlers are generally called from different concurrent contexts and therefore need to be @Sendable (and @escaping).
When you write your own method in Swift, the compiler expects you to put the right attributes on your methods. In this case, you've declared the method as taking a non-@Sendable, non-@escaping function. This works because you've given the method a toy implementation that always uses the completion handler immediately. If you gave it a more realistic implementation — one which, presumably, invokes the completion handler asynchronously after some event occurs — you will find that it needs to be at least @escaping and almost certainly also @Sendable.
As to @Sendable, the truth is all my code is on main queue so the closure doesn't need to be Sendable. I tried marking them so but still got the same error:
NS_SWIFT_UI_ACTOR
@interface Bar : NSObject
- (void)doSomethingWithCompletionHandler:(nullable void (^)(void))completion;
@end
- (void)doSomethingWithCompletionHandler:(void (^)(void))completion {
if (completion) {
completion();
}
}
@MainActor
@objc public final class DismissHandler: NSObject {
public func dismissViewController(completion: (() -> Void)?) {
let bar = Bar()
bar?.doSomething(completionHandler: completion) // <- Passing non-sendable parameter 'completion' to function expecting a @Sendable closure
let zar = Zar()
zar.doSomething(completionHandler: completion) // <- No error here
}
}
I meant on the parameter. The class being @MainActor doesn’t mean it promises to run its completion handlers there.
Making the completion handler non-sendable when the class is main-actor ends up having the same effect because the concurrent context it can’t be sent from is the main actor, thus it must be main-actor-isolated.