Kotlin Help

Interoperability with Swift/Objective-C

This document covers some details of Kotlin/Native interoperability with Swift/Objective-C.


Kotlin/Native provides bidirectional interoperability with Objective-C. Objective-C frameworks and libraries can be used in Kotlin code if properly imported to the build (system frameworks are imported by default). See compilation configurations for more details. A Swift library can be used in Kotlin code if its API is exported to Objective-C with @objc. Pure Swift modules are not yet supported.

Kotlin modules can be used in Swift/Objective-C code if compiled into a framework (see here for how to declare binaries). See Kotlin Multiplatform Mobile Sample for an example.

Hiding Kotlin declarations

If you don't want to export Kotlin declarations to Objective-C and Swift, use special annotations:

  • @HiddenFromObjC hides a Kotlin declaration from Objective-C and Swift. The annotation disables a function or property export to Objective-C, making your Kotlin code more Objective-C/Swift-friendly.

  • @ShouldRefineInSwift helps to replace a Kotlin declaration with a wrapper written in Swift. The annotation marks a function or property as swift_private in the generated Objective-C API. Such declarations get the __ prefix, which makes them invisible from Swift.

    You can still use these declarations in your Swift code to create a Swift-friendly API, but they won't be suggested in the Xcode autocomplete.

    For more information on refining Objective-C declarations in Swift, see the official Apple documentation.


The table below shows how Kotlin concepts are mapped to Swift/Objective-C and vice versa.

"->" and "<-" indicate that mapping only goes one way.



















note 1, note 2




note 1, note 2




note 1, note 2

@Throws fun






Category member


companion member <-

Class method or property

Class method or property





shared or companion property

shared or companion property


Primitive type

Primitive type / NSNumber


Unit return type






























Function type

Function type

Block pointer type


Inline classes




Name translation

Objective-C classes are imported into Kotlin with their original names. Protocols are imported as interfaces with Protocol name suffix, i.e. @protocol Foo-> interface FooProtocol. These classes and interfaces are placed into a package specified in build configuration (platform.* packages for preconfigured system frameworks).

The names of Kotlin classes and interfaces are prefixed when imported to Objective-C. The prefix is derived from the framework name.

Objective-C does not support packages in a framework. If the Kotlin compiler finds Kotlin classes in the same framework which have the same name but different packages, it renames them. This algorithm is not stable yet and can change between Kotlin releases. To work around this, you can rename the conflicting Kotlin classes in the framework.

To avoid renaming Kotlin declarations, use the @ObjCName annotation. It instructs the Kotlin compiler to use a custom Objective-C and Swift name for classes, interfaces, and other Kotlin concepts:

@ObjCName(swiftName = "MySwiftArray") class MyKotlinArray { @ObjCName("index") fun indexOf(@ObjCName("of") element: String): Int = TODO() } // Usage with the ObjCName annotations let array = MySwiftArray() let index = array.index(of: "element")


Swift/Objective-C initializers are imported to Kotlin as constructors and factory methods named create. The latter happens with initializers declared in the Objective-C category or as a Swift extension, because Kotlin has no concept of extension constructors.

Kotlin constructors are imported as initializers to Swift/Objective-C.


Writeable Objective-C properties overriding read-only properties of the superclass are represented as setFoo() method for the property foo. The same goes for a protocol's read-only properties that are implemented as mutable.

Top-level functions and properties

Top-level Kotlin functions and properties are accessible as members of special classes. Each Kotlin file is translated into such a class. E.g.

// MyLibraryUtils.kt package my.library fun foo() {}

can be called from Swift like


Method names translation

Generally, Swift argument labels and Objective-C selector pieces are mapped to Kotlin parameter names. These two concepts have different semantics, so sometimes Swift/Objective-C methods can be imported with a clashing Kotlin signature. In this case, the clashing methods can be called from Kotlin using named arguments, e.g.:

[player moveTo:LEFT byMeters:17] [player moveTo:UP byInches:42]

In Kotlin, it would be:

player.moveTo(LEFT, byMeters = 17) player.moveTo(UP, byInches = 42)

The methods of kotlin.Any (equals(), hashCode() and toString()) are mapped to the methods isEquals:, hash and description in Objective-C, and to the method isEquals(_:) and the properties hash, description in Swift.

You can specify a more idiomatic name in Swift or Objective-C, instead of renaming the Kotlin declaration. Use the @ObjCName annotation that instructs the Kotlin compiler to use a custom Objective-C and Swift name for methods or parameters.

Errors and exceptions

Kotlin has no concept of checked exceptions, all Kotlin exceptions are unchecked. Swift has only checked errors. So if Swift or Objective-C code calls a Kotlin method which throws an exception to be handled, then the Kotlin method should be marked with a @Throws annotation specifying a list of "expected" exception classes.

When compiling to the Objective-C/Swift framework, non-suspend functions that have or inherit the @Throws annotation are represented as NSError*-producing methods in Objective-C and as throws methods in Swift. Representations for suspend functions always have NSError*/Error parameter in completion handler.

When Kotlin function called from Swift/Objective-C code throws an exception which is an instance of one of the @Throws-specified classes or their subclasses, it is propagated as NSError. Other Kotlin exceptions reaching Swift/Objective-C are considered unhandled and cause program termination.

suspend functions without @Throws propagate only CancellationException as NSError. Non-suspend functions without @Throws don't propagate Kotlin exceptions at all.

Note that the opposite reversed translation is not implemented yet: Swift/Objective-C error-throwing methods aren't imported to Kotlin as exception-throwing.

Suspending functions

Kotlin's suspending functions (suspend) are presented in the generated Objective-C headers as functions with callbacks, or completion handlers in Swift/Objective-C terminology.

Starting from Swift 5.5, Kotlin's suspend functions are also available for calling from Swift as async functions without using the completion handlers. Currently, this functionality is highly experimental and has certain limitations. See this YouTrack issue for details.

Learn more about the async/await mechanism in Swift.

Extensions and category members

Members of Objective-C categories and Swift extensions are generally imported to Kotlin as extensions. That's why these declarations can't be overridden in Kotlin. And the extension initializers aren't available as Kotlin constructors.

Kotlin extensions to "regular" Kotlin classes are imported to Swift and Objective-C as extensions and category members, respectively. Kotlin extensions to other types are treated as top-level declarations with an additional receiver parameter. These types include:

  • Kotlin String type

  • Kotlin collection types and subtypes

  • Kotlin interface types

  • Kotlin primitive types

  • Kotlin inline classes

  • Kotlin Any type

  • Kotlin function types and subtypes

  • Objective-C classes and protocols

Kotlin singletons

Kotlin singleton (made with an object declaration, including companion object) is imported to Swift/Objective-C as a class with a single instance.

The instance is available through the shared and companion properties.

For the following Kotlin code:

object MyObject { val x = "Some value" } class MyClass { companion object { val x = "Some value" } }

Access these objects as follows:

MyObject.shared MyObject.shared.x MyClass.companion MyClass.Companion.shared


Kotlin primitive type boxes are mapped to special Swift/Objective-C classes. For example, kotlin.Int box is represented as KotlinInt class instance in Swift (or ${prefix}Int instance in Objective-C, where prefix is the framework names prefix). These classes are derived from NSNumber, so the instances are proper NSNumbers supporting all corresponding operations.

NSNumber type is not automatically translated to Kotlin primitive types when used as a Swift/Objective-C parameter type or return value. The reason is that NSNumber type doesn't provide enough information about a wrapped primitive value type, i.e. NSNumber is statically not known to be Byte, Boolean, or Double. So Kotlin primitive values should be cast to/from NSNumber manually (see below).


NSMutableString Objective-C class is not available from Kotlin. All instances of NSMutableString are copied when passed to Kotlin.


Kotlin collections are converted to Swift/Objective-C collections as described in the table above. Swift/Objective-C collections are mapped to Kotlin in the same way, except for NSMutableSet and NSMutableDictionary. NSMutableSet isn't converted to a Kotlin MutableSet. To pass an object for Kotlin MutableSet, you can create this kind of Kotlin collection explicitly by either creating it in Kotlin with e.g. mutableSetOf(), or using the KotlinMutableSet class in Swift (or ${prefix}MutableSet in Objective-C, where prefix is the framework names prefix). The same holds for MutableMap.

Function types

Kotlin function-typed objects (e.g. lambdas) are converted to Swift functions / Objective-C blocks. However, there is a difference in how types of parameters and return values are mapped when translating a function and a function type. In the latter case, primitive types are mapped to their boxed representation. Kotlin Unit return value is represented as a corresponding Unit singleton in Swift/Objective-C. The value of this singleton can be retrieved in the same way as it is for any other Kotlin object (see singletons in the table above). To sum the things up:

fun foo(block: (Int) -> Unit) { ... }

would be represented in Swift as

func foo(block: (KotlinInt) -> KotlinUnit)

and can be called like

foo { bar($0 as! Int32) return KotlinUnit() }


Objective-C supports "lightweight generics" defined on classes, with a relatively limited feature set. Swift can import generics defined on classes to help provide additional type information to the compiler.

Generic feature support for Objective-C and Swift differ from Kotlin, so the translation will inevitably lose some information, but the features supported retain meaningful information.


Objective-C generics do not support all features of either Kotlin or Swift, so there will be some information lost in the translation.

Generics can only be defined on classes, not on interfaces (protocols in Objective-C and Swift) or functions.


Kotlin and Swift both define nullability as part of the type specification, while Objective-C defines nullability on methods and properties of a type. As such, the following:

class Sample<T>() { fun myVal(): T }

will (logically) look like this:

class Sample<T>() { fun myVal(): T? }

In order to support a potentially nullable type, the Objective-C header needs to define myVal with a nullable return value.

To mitigate this, when defining your generic classes, if the generic type should never be null, provide a non-null type constraint:

class Sample<T : Any>() { fun myVal(): T }

That will force the Objective-C header to mark myVal as non-null.


Objective-C allows generics to be declared covariant or contravariant. Swift has no support for variance. Generic classes coming from Objective-C can be force-cast as needed.

data class SomeData(val num: Int = 42) : BaseData() class GenVarOut<out T : Any>(val arg: T)
let variOut = GenVarOut<SomeData>(arg: sd) let variOutAny : GenVarOut<BaseData> = variOut as! GenVarOut<BaseData>


In Kotlin, you can provide upper bounds for a generic type. Objective-C also supports this, but that support is unavailable in more complex cases, and is currently not supported in the Kotlin - Objective-C interop. The exception here being a non-null upper bound will make Objective-C methods/properties non-null.

To disable

To have the framework header written without generics, add the flag to the compiler config:

binaries.framework { freeCompilerArgs += "-Xno-objc-generics" }

Casting between mapped types

When writing Kotlin code, an object may need to be converted from a Kotlin type to the equivalent Swift/Objective-C type (or vice versa). In this case, a plain old Kotlin cast can be used, e.g.

val nsArray = listOf(1, 2, 3) as NSArray val string = nsString as String val nsNumber = 42 as NSNumber


Subclassing Kotlin classes and interfaces from Swift/Objective-C

Kotlin classes and interfaces can be subclassed by Swift/Objective-C classes and protocols.

Subclassing Swift/Objective-C classes and protocols from Kotlin

Swift/Objective-C classes and protocols can be subclassed with a Kotlin final class. Non-final Kotlin classes inheriting Swift/Objective-C types aren't supported yet, so it is not possible to declare a complex class hierarchy inheriting Swift/Objective-C types.

Normal methods can be overridden using the override Kotlin keyword. In this case, the overriding method must have the same parameter names as the overridden one.

Sometimes it is required to override initializers, e.g. when subclassing UIViewController. Initializers imported as Kotlin constructors can be overridden by Kotlin constructors marked with the @OverrideInit annotation:

class ViewController : UIViewController { @OverrideInit constructor(coder: NSCoder) : super(coder) ... }

The overriding constructor must have the same parameter names and types as the overridden one.

To override different methods with clashing Kotlin signatures, you can add a @Suppress("CONFLICTING_OVERLOADS") annotation to the class.

By default, the Kotlin/Native compiler doesn't allow calling a non-designated Objective-C initializer as a super(...) constructor. This behaviour can be inconvenient if the designated initializers aren't marked properly in the Objective-C library. Adding a disableDesignatedInitializerChecks = true to the .def file for this library would disable these compiler checks.

C features

See Interoperability with C for an example case where the library uses some plain C features, such as unsafe pointers, structs, and so on.

Export of KDoc comments to generated Objective-C headers

By default, KDocs documentation comments are not translated into corresponding comments when generating an Objective-C header.
For example, the following Kotlin code with KDoc:

/** * Prints the sum of the arguments. * Properly handles the case when the sum doesn't fit in 32-bit integer. */ fun printSum(a: Int, b: Int) = println(a.toLong() + b)

will produce an Objective-C declaration without any comments:

+ (void)printSumA:(int32_t)a b:(int32_t)b __attribute__((swift_name("printSum(a:b:)")));

To enable export of KDoc comments, add the following compiler option to your build.gradle(.kts):

kotlin { targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> { compilations.get("main").compilerOptions.options.freeCompilerArgs.add("-Xexport-kdoc") } }
kotlin { targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget) { compilations.get("main").compilerOptions.options.freeCompilerArgs.add("-Xexport-kdoc") } }

After that, the Objective-C header will contain a corresponding comment:

/** * Prints the sum of the arguments. * Properly handles the case when the sum doesn't fit in 32-bit integer. */ + (void)printSumA:(int32_t)a b:(int32_t)b __attribute__((swift_name("printSum(a:b:)")));

Known limitations:

  • Dependency documentation is not exported unless it is compiled with -Xexport-kdoc itself. The feature is experimental, so libraries compiled with this flag might be incompatible with other compiler versions.

  • KDoc comments are mostly exported "as is". Many KDoc features (for example, @property) are not supported.


Some features of Kotlin programming language are not yet mapped into respective features of Objective-C or Swift. Currently, the following features are not properly exposed in generated framework headers:

  • inline classes (arguments are mapped as either underlying primitive type or id)

  • custom classes implementing standard Kotlin collection interfaces (List, Map, Set) and other special classes

  • Kotlin subclasses of Objective-C classes

Last modified: 25 May 2023