
Kotlin-Swift interopedia
Overview
Kotlin/Native provides bidirectional interoperability with Objective-C. Kotlin is not directly interoperable with Swift but rather indirectly via an Objective-C bridge. The reason for this is twofold:
- It allows all iOS projects (written in Objective-C or Swift) to use shared Kotlin code
- When the decision was made, Swift was still on the road to maturity and mainstream adoption.
The Kotlin/Native compiler generates Objective-C headers, which Swift code can import. This has the following implications for Swift development:
- Some features work exactly as expected
- Some features work with a small workaround
- Some features work better with a community solution
- Some features don’t work optimally right now
- Some features don’t work
| Swift export, where the Kotlin API is directly exported as Swift declarations instead of Objective-C headers, is something that the Kotlin team is currently working on, and will resolve some of the difficulties experienced by Swift developers when consuming shared Kotlin code. You can find the table with the latest feature state here. |
How to use
Interopedia
This interopedia of the different Kotlin language features is categorized into broad categories, namely:
- Overview
- Functions and properties
- More about functions
- Types
- Classes and interfaces
- Coroutines
- Extensions
- Generics
Each language feature has its own article, consisting of an explanation of the feature, some sample code in Kotlin, how to call this code from Swift (if possible), and additional improvements should the Swift code not be as idiomatic as we’d like.
You could search the interopedia for the particular language feature that you are interested in, or read all the articles in order for a more comprehensive understanding of Kotlin/Swift interoperability.
Kotlin/Swift Interop Playground app
The iOS app is organized into the same broad categories as the interopedia. Clicking on a specific language feature will:
- Display a summary of the interoperability of the feature.
- Run code samples associated with the feature and print the results in the console.
You can edit the code, rerun the app, and see how the output has changed.
Overview
| Classes and functions | You can instantiate Kotlin classes and call Kotlin functions from Swift: SimpleClass().simpleFunction(). |
| Top-level functions | You can access a top-level function via the wrapper class: TopLevelFunctionKt.topLevelFunction(). |
| Types | Simple types and custom types can be passed as arguments and returned from function calls. |
| Collections | Kotlin and Swift have very similar kinds of collections and can be mapped between each other. |
| Exceptions | If you invoke a Kotlin function that throws an exception and doesn't declare it with `@Throws`, that crashes the app. Declared exceptions are converted to NSError and must be handled. |
| Public API | Public classes, functions, and properties are visible from Swift. Marking classes, functions, and properties internal will exclude them from the public API of the shared code, and they will not be visible in Swift. |
| Interop annotation - @ObjCName | Gives better Objective-C/Swift names to Kotlin constructs like classes, functions and so on, without actually renaming the Kotlin constructs. Experimental. |
| Interop annotations - @HiddenFromObj | Hides a Kotlin declaration from Objective-C/Swift. Experimental. |
| Interop annotations - @ShouldRefineInSwift | Helps to replace a Kotlin declaration with a wrapper written in Swift. Experimental. |
| KDoc comments | You can see certain KDoc comments at development time. In Xcode, use Option+Double left click to see the docs. Note that many KDocs features don't work in Xcode, like properties on constructors (@property) aren't visible. In Fleet, use the 'Show Documentation' action. |
Functions and properties
More about functions
Types
Classes and interfaces
| Abstract classes | Xcode has no hints to override abstract methods, rather we get a crash when trying to use the method during runtime. |
| Annotation classes | Annotations are not supported and are not included in the .h file. |
| Data classes | Some autogenerated functions are converted to Swift: copy to doCopy, equals to isEquals, toString to description. Additional features, like destructuring, are not supported. |
| Enum classes | No equivalent enum is generated on the Swift side, and default case must be specified in a switch expression. Instead an object with static elements is generated. Improved interop available with SKIE. |
| Inner classes | Minor differences in creation syntax. |
| Open classes | Can inherit from open class, use its protected properties, override open, but not override final methods. |
| Sealed classes | A class with heirs is generated. Passing to a switch statement requires a default case. Improved interop available with SKIE. |
| Inline classes | This feature is not supported. |
| Objects | You can access Kotlin object via the shared auxiliary object: MyKotlinObject.shared.myProperty. |
| Companion objects | You can access members of Kotlin companion objects from Swift explicitly through the `companion` auxiliary object: ClassWithCompanionObject.companion.CONST_VAL_EXAMPLE. |
| Fun interfaces | You can't create an anonymous class in Swift. |
| Interfaces | The interface has become @protocol. Xcode turns val property into var when generating the stubs. |
| Sealed interfaces | Separate protocols are generated that are not related to each other. |
Coroutines
| Suspend functions | Translated into callback, experimentally - into async / await. Libraries like SKIE and KMP-NativeCoroutines can be used to improve the interop and provide cancellation support. |
| Flows | Translated into callback, experimentally - into async / await. Generic type arguments are lost. Libraries like SKIE and KMP-NativeCoroutines can be used to improve the interop and provide cancellation support. |
Extensions
Generics
Feature Support Refresher
Some features work exactly as expected
- Classes and functions
- Member properties (Readonly or Mutable)
- Higher-order functions (lambda as Parameter or Return)
- Collections with custom types
- Unit and Nothing
- Abstract classes
- Open classes
- Interfaces
- Extension function over usual class
- Extension properties over usual class
Some features work with a small workaround
- Top-level functions
- Top-level properties (Read-only or Mutable)
- Exceptions
- Function overloads
- Functions with default arguments
- Functions expecting lambda with receiver
- Functions with receivers
- Basic types
- Optional basic types
- Collections with basic types
- Mutable / immutable collections
- Enum classes
- Inner classes
- Sealed classes
- Objects
- Companion objects
- Sealed interfaces
- Extension function over platform class
- Extension properties over platform class
- Extension properties for companion object of usual class
Some features work better with a community solution
Some features don’t work optimally right now (use with care)
- Data classes
- Generic classes
- Generic functions
- Contravariant generics
- Covariant generics
- Star projections
Some features don’t work (don’t use)
- Functions with value class parameter
- Functions with a vararg parameter
- Inline functions
- Annotations
- Inline classes
- Fun interfaces
- Extension properties for companion object of platform class
- Bounded generics
- Reified functions
- Generic interfaces