You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/topics/native/native-objc-interop.md
+68-24Lines changed: 68 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,7 +9,7 @@
9
9
>
10
10
{style="warning"}
11
11
12
-
This document covers some aspects of Kotlin/Native interoperability with Swift/Objective-C: how you can use Kotlin
12
+
Kotlin/Native provides indirect interoperability with Swift through Objective-C. This document covers how you can use Kotlin
13
13
declarations in Swift/Objective-C code and Objective-C declarations in Kotlin code.
14
14
15
15
Some other resources you might find useful:
@@ -43,12 +43,12 @@ Kotlin modules can be used in Swift/Objective-C code if compiled into a framewor
43
43
>
44
44
{style="warning"}
45
45
46
-
To make your Kotlin code more Objective-C/Swift-friendly, you can hide a Kotlin declaration from Objective-C and Swift
47
-
with `@HiddenFromObjC`. The annotation disables a function or property export to Objective-C.
46
+
To make your Kotlin code more Swift/Objective-C-friendly, use the `@HiddenFromObjC` annotation to hide a Kotlin declaration
47
+
from Objective-C and Swift. It disables the function or property export to Objective-C.
48
48
49
49
Alternatively, you can mark Kotlin declarations with the `internal` modifier to restrict their visibility in the
50
-
compilation module. Choose`@HiddenFromObjC` if you only want to hide the Kotlin declaration from Objective-C and Swift,
51
-
but still keep it visible from other Kotlin modules.
50
+
compilation module. Use`@HiddenFromObjC` if you want to hide the Kotlin declaration from Objective-C and Swift
51
+
while keeping it visible to other Kotlin modules.
52
52
53
53
[See an example in the Kotlin-Swift interopedia](https://github.com/kotlin-hands-on/kotlin-swift-interopedia/blob/main/docs/overview/HiddenFromObjC.md).
54
54
@@ -186,9 +186,9 @@ The table below shows how Kotlin concepts are mapped to Swift/Objective-C and vi
186
186
| `companion` member <- | Class method or property | Class method or property | |
187
187
| `null` | `nil` | `nil` | |
188
188
| `Singleton` | `shared` or `companion` property | `shared` or `companion` property | [note](#kotlin-singletons) |
189
-
| Primitive type | Primitive type / `NSNumber` | | [note](#nsnumber) |
189
+
| Primitive type | Primitive type / `NSNumber` | | [note](#primitive-types) |
@@ -240,7 +240,7 @@ Kotlin constructors are imported as initializers to Swift/Objective-C.
240
240
241
241
### Setters
242
242
243
-
Writeable Objective-C properties overriding read-only properties of the superclass are represented as `setFoo()` method
243
+
Writeable Objective-C properties overriding read-only properties of the superclass are represented as the `setFoo()` method
244
244
for the property `foo`. The same goes for a protocol's read-only properties that are implemented as mutable.
245
245
246
246
### Top-level functions and properties
@@ -304,12 +304,12 @@ All Kotlin exceptions are unchecked, meaning that errors are caught at runtime.
304
304
that are handled at compile time. So, if Swift or Objective-C code calls a Kotlin method that throws an exception,
305
305
the Kotlin method should be marked with the `@Throws` annotation, specifying a list of "expected" exception classes.
306
306
307
-
When compiling to the Objective-C/Swift framework, non-`suspend` functions that have or inherit the `@Throws` annotation
307
+
When compiling to the Swift/Objective-C framework, non-`suspend` functions that have or inherit the `@Throws` annotation
308
308
are represented as `NSError*`-producing methods in Objective-C and as `throws` methods in Swift.
309
-
Representations for `suspend` functions always have `NSError*`/`Error` parameter in completion handler.
309
+
Representations for `suspend` functions always have an `NSError*`/`Error` parameter in the completion handler.
310
310
311
-
When Kotlin function called from Swift/Objective-C code throws an exception which is an instance of one of
312
-
the `@Throws`-specified classes or their subclasses, it is propagated as `NSError`.
311
+
When a Kotlin function called from Swift/Objective-C code throws an exception which is an instance of one of
312
+
the classes specified with `@Throws`or their subclasses, the exception is propagated as an`NSError`.
313
313
Other Kotlin exceptions reaching Swift/Objective-C are considered unhandled and cause program termination.
314
314
315
315
`suspend` functions without `@Throws` propagate only `CancellationException` (as `NSError`).
@@ -438,28 +438,72 @@ See more examples in the Kotlin-Swift interopedia:
438
438
*[How to access Kotlin objects using `shared`](https://github.com/kotlin-hands-on/kotlin-swift-interopedia/blob/main/docs/classesandinterfaces/Objects.md)
439
439
*[How to access members of Kotlin companion objects from Swift](https://github.com/kotlin-hands-on/kotlin-swift-interopedia/blob/main/docs/classesandinterfaces/Companion%20objects.md).
440
440
441
-
### NSNumber
441
+
### Primitive types
442
442
443
443
Kotlin primitive type boxes are mapped to special Swift/Objective-C classes. For example, the `kotlin.Int` box is represented
444
-
as `KotlinInt` class instance in Swift (or `${prefix}Int` instance in Objective-C, where `prefix` is the framework names prefix).
444
+
as the `KotlinInt` class instance in Swift (or the `${prefix}Int` instance in Objective-C, where `prefix` is the framework's name prefix).
445
445
These classes are derived from `NSNumber`, so the instances are proper `NSNumber`s supporting all corresponding operations.
446
446
447
-
`NSNumber` type is not automatically translated to Kotlin primitive types when used as a Swift/Objective-C parameter type
448
-
or return value. The reason is that `NSNumber` type doesn't provide enough information about a wrapped primitive value
447
+
The `NSNumber` type is not automatically translated to Kotlin primitive types when used as a Swift/Objective-C parameter type
448
+
or return value. The reason is that the `NSNumber` type doesn't provide enough information about a wrapped primitive value
449
449
type, for example, `NSNumber` is statically not known to be `Byte`, `Boolean`, or `Double`. So Kotlin primitive values
450
450
should be [cast to and from `NSNumber` manually](#casting-between-mapped-types).
451
451
452
-
### NSMutableString
452
+
### Strings
453
+
454
+
When a Kotlin `String` is passed to Swift, it's first exported as an Objective-C object, and then the Swift compiler
455
+
copies it one more time for a Swift conversion. This results in additional runtime overhead.
456
+
457
+
To avoid that, access Kotlin strings in Swift directly as an Objective-C `NSString` instead.
458
+
[See the conversion example](#see-the-conversion-example).
459
+
460
+
#### NSMutableString
453
461
454
462
`NSMutableString` Objective-C class is not available from Kotlin.
455
463
All instances of `NSMutableString` are copied when passed to Kotlin.
456
464
457
465
### Collections
458
466
459
-
Kotlin collections are converted to Swift/Objective-C collections as described in the [table above](#mappings).
460
-
Swift/Objective-C collections are mapped to Kotlin in the same way, except for `NSMutableSet` and `NSMutableDictionary`.
467
+
#### Kotlin -> Objective-C -> Swift
468
+
469
+
When a Kotlin collection is passed to Swift, it's first converted to an Objective-C equivalent, and then the Swift compiler
470
+
copies the entire collection and converts it into a Swift-native collection as described in the [mappings table](#mappings).
471
+
472
+
This last conversion leads to performance costs. To prevent this, when using Kotlin collections in Swift,
473
+
explicitly cast them to their Objective-C counterparts: `NSDictionary`, `NSArray`, or `NSSet`.
474
+
475
+
##### See the conversion example {initial-collapse-state="collapsed" collapsible="true"}
476
+
477
+
For example, the following Kotlin declaration:
478
+
479
+
```kotlin
480
+
val map:Map<String, String>
481
+
```
482
+
483
+
In Swift, might look like this:
484
+
485
+
```Swift
486
+
map[key]?.count??0
487
+
```
488
+
489
+
Here, the `map` is implicitly converted to Swift's `Dictionary`, and its string values are mapped to Swift's `String`.
490
+
This results in a performance cost.
491
+
492
+
To avoid the conversion, explicitly cast `map` to Objective-C's `NSDictionary` and access values as `NSString` instead:
493
+
494
+
```Swift
495
+
let nsMap: NSDictionary = map as NSDictionary
496
+
(nsMap[key] as? NSString)?.length??0
497
+
```
498
+
499
+
This ensures that the Swift compiler doesn't perform an additional conversion step.
500
+
501
+
#### Swift -> Objective-C -> Kotlin
502
+
503
+
Swift/Objective-C collections are mapped to Kotlin as described in the [mappings table](#mappings),
504
+
except for `NSMutableSet` and `NSMutableDictionary`.
461
505
462
-
`NSMutableSet` isn't converted to a Kotlin `MutableSet`. To pass an object to Kotlin `MutableSet`, explicitly create this
506
+
`NSMutableSet` isn't converted to a Kotlin's`MutableSet`. To pass an object to Kotlin `MutableSet`, explicitly create this
463
507
kind of Kotlin collection. To do this, use, for example, the `mutableSetOf()` function in Kotlin or the
464
508
`KotlinMutableSet` class in Swift and `${prefix}MutableSet` in Objective-C (`prefix` is the framework names prefix).
465
509
The same is true for `MutableMap`.
@@ -499,7 +543,7 @@ foo {
499
543
500
544
### Generics
501
545
502
-
Objective-C supports "lightweight generics" defined on classes, with a relatively limited feature set. Swift can import
546
+
Objective-C supports "lightweight generics" defined in classes, with a relatively limited feature set. Swift can import
503
547
generics defined on classes to help provide additional type information to the compiler.
504
548
505
549
Generic feature support for Objective-C and Swift differ from Kotlin, so the translation will inevitably lose some
In Kotlin, you can provide upper bounds for a generic type. Objective-C also supports this, but that support is unavailable
567
-
in more complex cases, and is currently not supported in the Kotlin - Objective-C interop. The exception here being a non-nullable
611
+
in more complex cases and is currently not supported in the Kotlin - Objective-C interop. The exception here being a non-nullable
568
612
upper bound will make Objective-C methods/properties non-nullable.
569
613
570
614
#### To disable
@@ -670,7 +714,7 @@ The annotation instructs the Kotlin compiler to ignore conflicting overloads, in
670
714
argument types, but different argument names, are inherited from the Objective-C class.
671
715
672
716
By default, the Kotlin/Native compiler doesn't allow calling a non-designated Objective-C initializer as a `super()`
673
-
constructor. This behaviour can be inconvenient if the designated initializers aren't marked properly in the Objective-C
717
+
constructor. This behavior can be inconvenient if the designated initializers aren't marked properly in the Objective-C
674
718
library. To disable these compiler checks, add the `disableDesignatedInitializerChecks = true` to the library's [`.def` file](native-definition-file.md).
675
719
676
720
## C features
@@ -680,7 +724,7 @@ such as unsafe pointers, structs, and so on.
680
724
681
725
## Unsupported
682
726
683
-
Some features of Kotlin programming language are not yet mapped into the respective features of Objective-C or Swift.
727
+
Some features of the Kotlin programming language are not yet mapped into the respective features of Objective-C or Swift.
684
728
Currently, the following features are not properly exposed in generated framework headers:
685
729
686
730
* Inline classes (arguments are mapped as either underlying primitive type or `id`)
0 commit comments