From my understanding, optional closures are always implicitly escaping because they are boxed in an Optional that could theoretically escape.
I am currently writing a function that takes a (non-optional) closure and forwards it to UITableView
's performBatchUpdates(_:completion:)
. I was fully expecting to have to annotate the parameter as @escaping
, but it compiles just fine without the annotation. If I write a method with the same signature as performBatchUpdates(_:completion:)
and try to pass the closure to this method, however, the compiler correctly complains:
extension UITableView {
func f(updateData: () -> Void) {
// these two work
self.performBatchUpdates(updateData)
self.performBatchUpdates({ updateData() })
// these two don't
self._performBatchUpdates(updateData) // Cannot convert value of type '() -> Void' to expected argument type '(() -> Void)?'
self._performBatchUpdates({ updateData() }) // Escaping closure captures non-escaping parameter 'updateData'
}
// Same signature as UIKit's _performBatchUpdates(_:completion:)
// https://developer.apple.com/documentation/uikit/uitableview/2887515-performbatchupdates
func _performBatchUpdates(_ updates: (() -> Void)?, completion: ((Bool) -> Void)? = nil) {
}
}
What kind of magic is this? Are there some hidden annotations in UIKit's interface to allow for non-escaping optional closures?