and mistakes. 1. Question: How do I make my Kotlin/Swift interop look more like idiomatic Swift? 2. Question: Can I / how do I consume suspend functions and Flows from Swift? 3. Mistake: Misusing expect/actual building blocks. What this talk is about
with Objective-C, not Swift • Why? ◦ Can be used in all iOS projects, not just Swift ones ◦ Swift was still on the road to maturity/adoption at that stage Kotlin/Objective-C interop
from Swift • Lots of code samples • Gives workarounds / community solutions • Includes playground app with runnable samples Kotlin/Swift Interopedia [kotl.in/interopedia]
{ println(LOGIN_SCREEN_NAME) } } Slight modification example - Objects ✓ Property called ‘shared’ appears Used from Kotlin: AnalyticsLogger.LOGIN_SCREEN_NAME AnalyticsLogger.logLogin() Used from Swift:
Swift • Stepping stone to official Swift interop • List of features always growing, but for now: ◦ Enumerations (enums, sealed hierarchies) ◦ Functions (default arguments etc) ◦ Reactive (coroutines and Flows) [next section] SKIE [https://skie.touchlab.co/]
.red: return "R" case .green: return "G" case .blue: return "B" default: return "D" } } Enum Interop - from Swift Somewhere in Swift Required: Switch must be exhaustive
\(body)"); case is NetworkResponse.Error: print("Error"); default: print("Default") } } Sealed Classes Interop - from Swift Somewhere in Swift Required: Switch must be exhaustive
case data(ComposeApp.NetworkResponse.Data) case error(ComposeApp.NetworkResponse.Error) } } SKIE Sealed Classes Interop - The Investigation Somewhere in Swift
if let sealed = sealed as? ComposeApp.NetworkResponse.Data { return ComposeApp.Skie.KotlinProject__composeApp.NetworkResponse.__Sealed.data(seal ed) } else if let sealed = sealed as? ComposeApp.NetworkResponse.Error { return ComposeApp.Skie.KotlinProject__composeApp.NetworkResponse.__Sealed.error(sea led) } else { fatalError("Unknown subtype. This error should not happen under normal circumstances since SirClass: ComposeApp.NetworkResponse is sealed.") } } SKIE Sealed Classes Interop - The Investigation Somewhere in Swift
if let sealed = sealed as? ComposeApp.NetworkResponse.Data { return ComposeApp.Skie.KotlinProject__composeApp.NetworkResponse.__Sealed.data(seal ed) } else if let sealed = sealed as? ComposeApp.NetworkResponse.Error { return ComposeApp.Skie.KotlinProject__composeApp.NetworkResponse.__Sealed.error(sea led) } else { fatalError("Unknown subtype. This error should not happen under normal circumstances since SirClass: ComposeApp.NetworkResponse is sealed.") } } SKIE Sealed Classes Interop - The Investigation Somewhere in Swift
if let sealed = sealed as? ComposeApp.NetworkResponse.Data { return ComposeApp.Skie.KotlinProject__composeApp.NetworkResponse.__Sealed.data(seal ed) } else if let sealed = sealed as? ComposeApp.NetworkResponse.Error { return ComposeApp.Skie.KotlinProject__composeApp.NetworkResponse.__Sealed.error(sea led) } else { fatalError("Unknown subtype. This error should not happen under normal circumstances since SirClass: ComposeApp.NetworkResponse is sealed.") } } SKIE Sealed Classes Interop - The Investigation Somewhere in Swift
if let sealed = sealed as? ComposeApp.NetworkResponse.Data { return ComposeApp.Skie.KotlinProject__composeApp.NetworkResponse.__Sealed.data(seal ed) } else if let sealed = sealed as? ComposeApp.NetworkResponse.Error { return ComposeApp.Skie.KotlinProject__composeApp.NetworkResponse.__Sealed.error(sea led) } else { fatalError("Unknown subtype. This error should not happen under normal circumstances since SirClass: ComposeApp.NetworkResponse is sealed.") } } SKIE Sealed Classes Interop - The Investigation Somewhere in Swift
compiler • Requires no additional work after setup • Supports async/await, while Combine, RxSwift require adapters • Offers other features to produce a Swift-friendly API from Kotlin
fun randomUUID() = UUID.randomUUID().toString() import platform.Foundation.NSUUID actual fun randomUUID(): String = NSUUID().UUIDString() expect fun randomUUID(): String Expect/actual functions