Skip to main content

Combine (preview)

SKIE has a preview support for bridging Kotlin Coroutines with Apple's Combine framework. This allows you to use Kotlin Coroutines in Swift code that uses Combine. The bridging supports converting suspend functions into Combine.Future types, and Flows into Combine.Publisher types.

Since Combine is usually being replaced with Swift Concurrency, we added this feature on top of the SKIE's native support for bridging Kotlin Coroutines with Swift Concurrency.

Each of these features can be enabled separately using the SKIE Gradle configuration.

suspend funCombine.Future

To enable the support for Combine.Future, add the following to your build.gradle.kts:

skie {
features {
enableFutureCombineExtensionPreview = true
}
}

When enabled, SKIE will extend Combine.Future with an initializer accepting any async lambda. With it, you can easily convert any suspend function into Combine.Future. Let's take a look at an example usage. We'll declare a suspending global function helloWorld.

suspend fun helloWorld(): String {
return "Hello World!"
}

Then in Swift you can use the new Future initializer like so:

let future = Future(async: helloWorld)
future.sink { error in
// Handle an error throw by the function.
// Note that this could also be `CancellationError`.
} receiveValue: { value in
// Value is a `String` "Hello World!"
print(value)
}
note

It's important to understand how Combine and its operators work. The example above doesn't store the cancellable returned by sink, so it would immediately cancel and receiveValue wouldn't get called. Additionally, Futures are hot and will invoke the provided async immediately. This means Futures don't wait for calling .sink on them. Futures also don't support cancellation.

FlowCombine.Publisher

To enable the support for Combine.Publisher, add the following to your build.gradle.kts:

skie {
features {
enableFlowCombineConvertorPreview = true
}
}

When enabled, each Flow bridged to Swift by SKIE will contain a toPublisher() method. Use this if you need to interface with Combine code and can't use Swift's native AsyncSequence. Let's take a look at an example usage. We'll declare a global function helloWorld returning a Flow.

fun helloWorld(): Flow<String> {
return flow {
emit("Hello")
delay(1.seconds)
emit("World")
delay(1.seconds)
emit("!")
}
}

Then in Swift you can use the toPublisher() function.

let publisher = helloWorld().toPublisher()
publisher.sink { value in
// Value is a `String` type
// Receives with a 1-second delay between them:
// - "Hello"
// - "World"
// - "!"
}
note

It's important to understand how Combine and its operators work. The example above doesn't store the cancellable returned by sink, so it would immediately cancel and receiveValue wouldn't get called.