Closures
Swift closures whose parameter and return types are all exported map directly to Kotlin/Java lambdas. This lets you pass callbacks from Kotlin into Swift and have Swift call them.
Passing a callback to Swift
Section titled “Passing a callback to Swift”Define a Swift method that accepts a closure:
import Swift4j
@jvmclass GreetingService { func greet(name: String, _ response: (Greeting) -> Void) { response(Greeting(name: name)) }}
@jvmclass Greeting { let name: String init(name: String) { self.name = name } func getMessage() -> String { "Hello from Swift, \(name)!" }}Both Greeting (the closure parameter type) and GreetingService must be annotated with @jvm. Any type that appears in a closure signature must be exported.
Call it from Kotlin by passing a lambda:
val service = GreetingService()
service.greet("Kotlin") { greeting -> println(greeting.getMessage())}Closures returning values
Section titled “Closures returning values”Closures can return values. The return type must be an exported type or a primitive:
@jvmclass Arrays { static func mapReversed(_ arr: [Int], mapping: (Int) -> Int) -> [Int] { arr.reversed().map(mapping) }}val result = Arrays.mapReversed(longArrayOf(1, 2, 3)) { it * 2 }// result: [6, 4, 2]Optional closures
Section titled “Optional closures”Closure parameters may be optional. Pass null from Kotlin to omit the callback:
@jvmstruct Task { func run(completion: (() -> Void)? = nil) { // ... do work ... completion?() }}val task = Task()task.run(completion: null) // no callbacktask.run { println("done") }Calling Swift from a closure
Section titled “Calling Swift from a closure”Closures are called synchronously by default. If the Swift method stores the closure and calls it later (e.g. from a background thread), make sure the Kotlin lambda does not capture JVM-thread-local state that may be unavailable on the calling thread.
For asynchronous patterns, consider using async methods instead — see Async.