Swift/Objective-C との相互運用
Objective-Cライブラリのインポートはベータ版です。 Objective-Cライブラリからcinteropツールによって生成されるすべてのKotlin宣言には、
@ExperimentalForeignApiアノテーションを付与する必要があります。Kotlin/Nativeに同梱されているネイティブプラットフォームライブラリ(Foundation、UIKit、POSIXなど)は、 一部のAPIでのみオプトインが必要です。
Kotlin/Nativeは、Objective-Cを介してSwiftとの間接的な相互運用性を提供します。このドキュメントでは、Swift/Objective-CコードでKotlin宣言を使用する方法と、KotlinコードでObjective-C宣言を使用する方法について説明します。
他に役立つ可能性のあるリソース:
- Kotlin-Swift interopedia(SwiftコードでKotlin宣言を使用する方法の例集)。
- Swift/Objective-C ARCとの統合セクション(KotlinのトレースGCとObjective-CのARC間の統合の詳細を説明)。
KotlinへのSwift/Objective-Cライブラリのインポート
Objective-Cのフレームワークとライブラリは、ビルドに適切にインポートされていれば(システムフレームワークはデフォルトでインポートされます)、Kotlinコードで使用できます。 詳細については、以下を参照してください:
Swiftライブラリは、そのAPIが@objcでObjective-Cにエクスポートされていれば、Kotlinコードで使用できます。 純粋なSwiftモジュールはまだサポートされていません。
Swift/Objective-CでのKotlinの使用
Kotlinモジュールは、フレームワークにコンパイルされていれば、Swift/Objective-Cコードで使用できます。
- バイナリの宣言方法については、最終的なネイティブバイナリのビルドを参照してください。
- 例については、Kotlin Multiplatformサンプルプロジェクトを確認してください。
Objective-CとSwiftからKotlin宣言を隠す
KotlinコードをSwift/Objective-Cによりフレンドリーにするには、@HiddenFromObjCアノテーションを使用してKotlin宣言をObjective-CおよびSwiftから隠します。これは、関数またはプロパティのObjective-Cへのエクスポートを無効にします。
あるいは、Kotlin宣言にinternal修飾子を付けて、コンパイルモジュール内での可視性を制限することもできます。他のKotlinモジュールからは見えるようにしつつ、Objective-CとSwiftからKotlin宣言を隠したい場合は、@HiddenFromObjCを使用します。
Kotlin-Swift interopediaで例を見る。
Swiftでのリファインの使用
@ShouldRefineInSwiftは、Kotlin宣言をSwiftで書かれたラッパーに置き換えるのに役立ちます。このアノテーションは、生成されるObjective-C APIで関数またはプロパティをswift_privateとしてマークします。このような宣言には__プレフィックスが付き、Swiftからは見えなくなります。
SwiftフレンドリーなAPIを作成するために、Swiftコードでこれらの宣言を使用することはできますが、Xcodeのオートコンプリートでは提案されません。
- SwiftでのObjective-C宣言のリファインの詳細については、Apple公式ドキュメントを参照してください。
@ShouldRefineInSwiftアノテーションの使用例については、Kotlin-Swift interopediaを参照してください。
宣言名の変更
Kotlin宣言の名前変更を避けるには、@ObjCNameアノテーションを使用します。これは、Kotlinコンパイラに、アノテーションが付けられたクラス、インターフェース、または他のKotlinエンティティに対して、カスタムのObjective-CおよびSwift名を使用するように指示します。
@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")Kotlin-Swift interopediaで別の例を見る。
KDocコメントによるドキュメントの提供
ドキュメントは、あらゆるAPIを理解するために不可欠です。共有Kotlin APIのドキュメントを提供することで、そのユーザーと使用法、注意点などについてやり取りできます。
Objective-Cヘッダーを生成する際、KotlinコードのKDocコメントは、対応するObjective-Cコメントに変換されます。例えば、KDocを含む以下のKotlinコード:
/**
* 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)は、対応するコメントを含むObjective-Cヘッダーを生成します:
/**
* 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:)")));KDocコメントはklibに組み込まれ、klibから生成されたAppleフレームワークに抽出されます。 その結果、クラスやメソッドのコメントは、例えばXcodeでのオートコンプリート時に表示されます。 .hファイル内の関数の定義に移動すると、@param、@returnなどのタグに関するコメントが表示されます。
既知の制限事項:
- 依存関係のドキュメントは、それ自体が
-Xexport-kdocオプションでコンパイルされていない限りエクスポートされません。このコンパイラオプションでコンパイルされたライブラリは、他のコンパイラバージョンと互換性がない可能性があります。 - KDocコメントはほとんどそのままエクスポートされますが、
@propertyなど、多くのKDocブロックタグはサポートされていません。
必要に応じて、Gradleビルドファイルのbinaries {}ブロックで、klibから生成されたAppleフレームワークへのKDocコメントのエクスポートを無効にすることができます。
// build.gradle.kts
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
kotlin {
iosArm64 {
binaries {
framework {
baseName = "sdk"
@OptIn(ExperimentalKotlinGradlePluginApi::class)
exportKdoc.set(false)
}
}
}
}マッピング
下の表は、Kotlinの概念がSwift/Objective-Cに、またその逆方向にもどのようにマッピングされるかを示しています。
->と<-は、マッピングが一方向のみであることを示します。
| Kotlin | Swift | Objective-C | Notes |
|---|---|---|---|
class | class | @interface | 注 |
interface | protocol | @protocol | |
constructor/create | Initializer | Initializer | 注 |
| プロパティ | Property | Property | 注 1, 注 2 |
| メソッド | Method | Method | 注 1, 注 2 |
enum class | class | @interface | 注 |
suspend -> | completionHandler:/ async | completionHandler: | 注 1, 注 2 |
@Throws fun | throws | error:(NSError**)error | 注 |
| 拡張 | Extension | Category member | 注 |
companionメンバー <- | Class method or property | Class method or property | |
null | nil | nil | |
| シングルトン | shared or companion property | shared or companion property | 注 |
| プリミティブ型 | Primitive type / NSNumber | 注 | |
Unit戻り値の型 | Void | void | |
String | String | NSString | 注 |
String | NSMutableString | NSMutableString | 注 |
List | Array | NSArray | |
MutableList | NSMutableArray | NSMutableArray | |
Set | Set | NSSet | |
MutableSet | NSMutableSet | NSMutableSet | 注 |
Map | Dictionary | NSDictionary | |
MutableMap | NSMutableDictionary | NSMutableDictionary | 注 |
| 関数型 | Function type | Block pointer type | 注 |
| インラインクラス | Unsupported | Unsupported | 注 |
クラス
名前変換
Objective-Cのクラスは、元の名前でKotlinにインポートされます。 プロトコルは、Protocolという名前のサフィックスを持つインターフェースとしてインポートされます。例えば、@protocol Foo -> interface FooProtocol。 これらのクラスとインターフェースは、ビルド設定で指定されたパッケージ(事前設定されたシステムフレームワークの場合はplatform.*パッケージ)に配置されます。
Kotlinのクラスとインターフェースの名前は、Objective-Cにインポートされる際にプレフィックスが付けられます。 プレフィックスはフレームワーク名から派生します。
Objective-Cはフレームワーク内のパッケージをサポートしていません。Kotlinコンパイラが同じフレームワーク内で同じ名前だが異なるパッケージを持つKotlinクラスを見つけた場合、それらの名前を変更します。このアルゴリズムはまだ安定しておらず、Kotlinのリリース間で変更される可能性があります。これを回避するには、フレームワーク内の競合するKotlinクラスの名前を変更できます。
強リンク
KotlinソースでObjective-Cクラスを使用すると、それは強リンクされたシンボルとしてマークされます。結果として生成されるビルド成果物には、関連するシンボルが強力な外部参照として記載されます。
これは、アプリが起動時にシンボルを動的にリンクしようとし、それらが利用できない場合はアプリがクラッシュすることを意味します。シンボルが一度も使用されなかったとしても、クラッシュは発生します。シンボルが特定のデバイスやOSバージョンで利用できない場合があります。
この問題を回避し、「シンボルが見つかりません」エラーを避けるには、クラスが実際に利用可能であるかをチェックするSwiftまたはObjective-Cのラッパーを使用してください。Compose Multiplatformフレームワークでこの回避策がどのように実装されたかを参照してください。
イニシャライザ
Swift/Objective-Cのイニシャライザは、Kotlinにはコンストラクタまたはcreateという名前のファクトリメソッドとしてインポートされます。 後者は、Objective-CカテゴリまたはSwift拡張で宣言されたイニシャライザで発生します。これはKotlinに拡張コンストラクタの概念がないためです。
SwiftのイニシャライザをKotlinにインポートする前に、
@objcでアノテーションを付けることを忘れないでください。
Kotlinのコンストラクタは、Swift/Objective-Cにはイニシャライザとしてインポートされます。
セッター
スーパークラスの読み取り専用プロパティをオーバーライドする書き込み可能なObjective-Cプロパティは、プロパティfooのsetFoo()メソッドとして表現されます。可変として実装されたプロトコルの読み取り専用プロパティも同様です。
トップレベル関数とプロパティ
トップレベルのKotlin関数とプロパティは、特殊なクラスのメンバーとしてアクセスできます。 各Kotlinファイルは、例えば以下のように、そのようなクラスに変換されます。
// MyLibraryUtils.kt
package my.library
fun foo() {}その後、Swiftからfoo()関数を次のように呼び出すことができます。
MyLibraryUtilsKt.foo()Kotlin-Swift interopediaでトップレベルのKotlin宣言にアクセスする例集を参照してください:
メソッド名の変換
通常、Swiftの引数ラベルとObjective-Cのセレクタ要素は、Kotlinのパラメータ名にマッピングされます。これら2つの概念は異なるセマンティクスを持つため、Swift/Objective-Cのメソッドが、競合するKotlinシグネチャでインポートされることがあります。この場合、競合するメソッドは、例えば以下のように名前付き引数を使用してKotlinから呼び出すことができます。
[player moveTo:LEFT byMeters:17]
[player moveTo:UP byInches:42]Kotlinでは、次のようになります。
player.moveTo(LEFT, byMeters = 17)
player.moveTo(UP, byInches = 42)kotlin.Anyの関数はSwift/Objective-Cに次のようにマッピングされます。
| Kotlin | Swift | Objective-C |
|---|---|---|
equals() | isEquals(_:) | isEquals: |
hashCode() | hash | hash |
toString() | description | description |
Kotlin-Swift interopediaのデータクラスの例を見る。
@ObjCNameアノテーションでKotlin宣言の名前を変更する代わりに、SwiftまたはObjective-Cでより慣用的な名前を指定できます。
エラーと例外
すべてのKotlin例外は非チェック例外であり、エラーは実行時に捕捉されます。しかし、Swiftにはコンパイル時に処理されるチェック済みエラーしかありません。したがって、SwiftまたはObjective-Cコードが例外をスローするKotlinメソッドを呼び出す場合、そのKotlinメソッドには、"予期される"例外クラスのリストを指定する@Throwsアノテーションを付ける必要があります。
Swift/Objective-Cフレームワークにコンパイルする際、@Throwsアノテーションを持つか継承する非suspend関数は、Objective-CではNSError*を生成するメソッドとして、Swiftではthrowsメソッドとして表現されます。suspend関数の表現は、常に完了ハンドラ内にNSError*/Errorパラメータを持ちます。
Swift/Objective-Cコードから呼び出されたKotlin関数が、@Throwsで指定されたクラスまたはそのサブクラスのいずれかのインスタンスである例外をスローした場合、その例外はNSErrorとして伝播されます。Swift/Objective-Cに到達する他のKotlin例外は未処理と見なされ、プログラムの終了を引き起こします。
@Throwsなしのsuspend関数は、CancellationExceptionのみを伝播します(NSErrorとして)。@Throwsなしの非suspend関数は、Kotlin例外をまったく伝播しません。
逆方向の変換はまだ実装されていません。Swift/Objective-Cのエラーをスローするメソッドは、Kotlinに例外をスローするメソッドとしてインポートされません。
Kotlin-Swift interopediaで例を見る。
Enum
KotlinのenumはObjective-Cに@interfaceとして、Swiftにclassとしてインポートされます。 これらのデータ構造には、各enum値に対応するプロパティがあります。このKotlinコードを考えてみましょう:
// Kotlin
enum class Colors {
RED, GREEN, BLUE
}このenumクラスのプロパティには、Swiftから次のようにアクセスできます。
// Swift
Colors.red
Colors.green
Colors.blueKotlin enumの変数をSwiftのswitch文で使用するには、コンパイルエラーを防ぐためにdefault文を提供します。
switch color {
case .red: print("It's red")
case .green: print("It's green")
case .blue: print("It's blue")
default: fatalError("No such color")
}Kotlin-Swift interopediaで別の例を見る。
suspend 関数
Kotlinのサスペンド関数(suspend)は、生成されるObjective-Cヘッダーではコールバック付き関数として、Swift/Objective-Cの用語では[完了ハンドラ](https://developer.apple.com/documentation/swift/calling_objective-c_apis_ asynchronously)として表現されます。
Swift 5.5以降、Kotlinのsuspend関数は、完了ハンドラを使用せずにasync関数としてSwiftから呼び出すことも可能です。現在、この機能は非常に実験的であり、特定の制限があります。詳細については、このYouTrackの課題を参照してください。
- Swiftドキュメントの
async/awaitメカニズムについてさらに学ぶ。 - Kotlin-Swift interopediaで、同じ機能を実装するサードパーティライブラリの例と推奨事項を参照する。
拡張とカテゴリメンバー
Objective-CカテゴリおよびSwift拡張のメンバーは、一般的にKotlinに拡張としてインポートされます。そのため、これらの宣言はKotlinでオーバーライドできず、拡張イニシャライザはKotlinコンストラクタとしては利用できません。
現在、2つの例外があります。Kotlin 1.8.20以降、NSViewクラス(AppKitフレームワークから)またはUIViewクラス(UIKitフレームワークから)と同じヘッダーで宣言されているカテゴリメンバーは、これらのクラスのメンバーとしてインポートされます。これは、NSViewまたはUIViewをサブクラス化するメソッドをオーバーライドできることを意味します。
「通常の」KotlinクラスへのKotlin拡張は、それぞれSwiftおよびObjective-Cに拡張およびカテゴリメンバーとしてインポートされます。他の型へのKotlin拡張は、追加のレシーバーパラメータを持つトップレベル宣言として扱われます。これらの型には以下が含まれます:
- Kotlinの
String型 - Kotlinのコレクション型とそのサブタイプ
- Kotlinの
interface型 - Kotlinのプリミティブ型
- Kotlinの
inlineクラス - Kotlinの
Any型 - Kotlinの関数型とそのサブタイプ
- Objective-Cのクラスとプロトコル
Kotlin-Swift interopediaで例集を見る。
Kotlinシングルトン
Kotlinのシングルトン(object宣言、companion objectを含む)は、Swift/Objective-Cに単一インスタンスを持つクラスとしてインポートされます。
インスタンスはsharedおよびcompanionプロパティを通じて利用できます。
次のKotlinコードの場合:
object MyObject {
val x = "Some value"
}
class MyClass {
companion object {
val x = "Some value"
}
}これらのオブジェクトには次のようにアクセスします:
MyObject.shared
MyObject.shared.x
MyClass.companion
MyClass.Companion.sharedObjective-Cでの
[MySingleton mySingleton]およびSwiftでのMySingleton()によるオブジェクトへのアクセスは非推奨になりました。
Kotlin-Swift interopediaでさらに多くの例を見る:
プリミティブ型
Kotlinのプリミティブ型ボックスは、特殊なSwift/Objective-Cクラスにマッピングされます。例えば、kotlin.Intボックスは、SwiftではKotlinIntクラスのインスタンスとして(またはObjective-Cでは${prefix}Intインスタンスとして、ここでprefixはフレームワークの名前プレフィックスです)表現されます。これらのクラスはNSNumberから派生しているため、インスタンスは対応するすべての操作をサポートする適切なNSNumberです。
NSNumber型は、Swift/Objective-Cのパラメータ型または戻り値として使用された場合、Kotlinプリミティブ型に自動的に変換されません。その理由は、NSNumber型がラップされたプリミティブ値の型に関する十分な情報を提供しないためです。例えば、NSNumberがByte、Boolean、またはDoubleであることは静的に分かりません。したがって、Kotlinのプリミティブ値は、手動でNSNumberとの間でキャストする必要があります。
文字列
KotlinのStringがSwiftに渡される際、まずObjective-Cオブジェクトとしてエクスポートされ、その後SwiftコンパイラがSwiftへの変換のためにもう一度コピーします。これにより、追加のランタイムオーバーヘッドが発生します。
それを避けるには、SwiftでKotlin文字列にObjective-CのNSStringとして直接アクセスします。変換例を見る。
NSMutableString
NSMutableString Objective-CクラスはKotlinからは利用できません。 NSMutableStringのすべてのインスタンスは、Kotlinに渡される際にコピーされます。
コレクション
Kotlin -> Objective-C -> Swift
KotlinコレクションがSwiftに渡される際、まずObjective-Cの同等物に変換され、その後Swiftコンパイラがコレクション全体をコピーし、マッピング表に記載されているようにSwiftネイティブのコレクションに変換します。
この最後の変換はパフォーマンスコストにつながります。これを防ぐには、SwiftでKotlinコレクションを使用する際に、明示的にObjective-Cの対応する型(NSDictionary、NSArray、NSSet)にキャストします。
変換例を見る
例えば、以下のKotlin宣言:
val map: Map<String, String>Swiftでは、次のようになるかもしれません:
map[key]?.count ?? 0ここで、mapは暗黙的にSwiftのDictionaryに変換され、その文字列値はSwiftのStringにマッピングされます。これによりパフォーマンスコストが発生します。
変換を避けるには、mapを明示的にObjective-CのNSDictionaryにキャストし、代わりに値をNSStringとしてアクセスします。
let nsMap: NSDictionary = map as NSDictionary
(nsMap[key] as? NSString)?.length ?? 0これにより、Swiftコンパイラが追加の変換ステップを実行しないことが保証されます。
Swift -> Objective-C -> Kotlin
Swift/Objective-Cコレクションは、NSMutableSetおよびNSMutableDictionaryを除き、マッピング表に記載されているとおりにKotlinにマッピングされます。
NSMutableSetはKotlinのMutableSetには変換されません。オブジェクトをKotlinのMutableSetに渡すには、この種のKotlinコレクションを明示的に作成します。これを行うには、例えばKotlinのmutableSetOf()関数、またはSwiftのKotlinMutableSetクラスとObjective-Cの${prefix}MutableSet(prefixはフレームワーク名のプレフィックス)を使用します。MutableMapについても同様です。
Kotlin-Swift interopediaで例を見る。
関数型
Kotlinの関数型オブジェクト(例:ラムダ)は、Swiftではクロージャに、Objective-Cではブロックに変換されます。Kotlin-Swift interopediaのラムダを持つKotlin関数の例を見る。
しかし、関数と関数型を変換する際、パラメータと戻り値の型のマッピング方法には違いがあります。後者の場合、プリミティブ型はボックス化された表現にマッピングされます。KotlinのUnit戻り値は、Swift/Objective-Cでは対応するUnitシングルトンとして表現されます。このシングルトンの値は、他のKotlinのobjectと同じ方法で取得できます。シングルトンは上記の表を参照してください。
以下のKotlin関数を考えてみましょう:
fun foo(block: (Int) -> Unit) { ... }Swiftでは次のように表現されます:
func foo(block: (KotlinInt) -> KotlinUnit)そして、次のように呼び出すことができます:
foo {
bar($0 as! Int32)
return KotlinUnit()
}Objective-Cブロック型での明示的なパラメータ名
エクスポートされたObjective-Cヘッダーに対して、Kotlinの関数型に明示的なパラメータ名を追加できます。それらがないと、XcodeのオートコンプリートはObjective-Cブロックでパラメータ名のないObjective-C関数の呼び出しを提案し、生成されたブロックはClang警告を引き起こします。
明示的なパラメータ名を有効にするには、以下のバイナリオプションをgradle.propertiesファイルに追加します。
kotlin.native.binary.objcExportBlockExplicitParameterNames=true例えば、以下のKotlinコードの場合:
// Kotlin:
fun greetUser(block: (name: String) -> Unit) = block("John")KotlinはKotlin関数型からObjective-Cブロック型にパラメータ名を転送し、Xcodeが提案でそれらを使用できるようにします:
// Objective-C:
greetUserBlock:^(NSString *name) {
// ...
};このオプションはObjective-C相互運用のみに影響します。これは、Xcodeで生成されたObjective-CコードをObjective-Cから呼び出す場合に適用され、一般的にSwiftからの呼び出しには影響しません。
ジェネリクス
Objective-Cは、比較的限られた機能セットを持つ、クラスで定義された「軽量ジェネリクス」をサポートしています。Swiftは、クラスで定義されたジェネリクスをインポートして、コンパイラに追加の型情報を提供するのに役立ちます。
Objective-CとSwiftのジェネリクス機能のサポートはKotlinとは異なるため、変換では必然的に一部の情報が失われますが、サポートされる機能は意味のある情報を保持します。
SwiftでKotlinジェネリクスを使用する方法の具体的な例については、Kotlin-Swift interopediaを参照してください。
制限事項
Objective-Cのジェネリクスは、KotlinまたはSwiftのすべての機能をサポートしているわけではないため、変換時に一部の情報が失われます。
ジェネリクスはクラスのみに定義でき、インターフェース(Objective-CおよびSwiftのプロトコル)や関数には定義できません。
ヌル許容性
KotlinとSwiftはどちらも型指定の一部としてヌル許容性を定義しますが、Objective-Cは型のメソッドとプロパティに対してヌル許容性を定義します。したがって、以下のKotlinコード:
class Sample<T>() {
fun myVal(): T
}Swiftでは次のようになります:
class Sample<T>() {
fun myVal(): T?
}潜在的にヌル許容の型をサポートするには、Objective-CヘッダーでmyValをヌル許容の戻り値を持つものとして定義する必要があります。
これを軽減するには、ジェネリッククラスを定義する際、ジェネリック型が_決して_ヌルであってはならない場合に、非ヌル許容の型制約を提供します。
class Sample<T : Any>() {
fun myVal(): T
}これにより、Objective-CヘッダーはmyValを非ヌル許容としてマークするよう強制されます。
共変性・反変性
Objective-Cでは、ジェネリクスを共変または反変として宣言できます。Swiftには分散性のサポートがありません。Objective-Cから来るジェネリッククラスは、必要に応じて強制キャストできます。
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>制約
Kotlinでは、ジェネリック型に上限(upper bounds)を指定できます。Objective-Cもこれをサポートしていますが、より複雑なケースではそのサポートは利用できず、現在のKotlin-Objective-C相互運用ではサポートされていません。ここでの例外は、非ヌル許容の上限がある場合、Objective-Cのメソッド/プロパティが非ヌル許容になることです。
無効にするには
フレームワークヘッダーをジェネリクスなしで生成するには、ビルドファイルに以下のコンパイラオプションを追加します。
binaries.framework {
freeCompilerArgs += "-Xno-objc-generics"
}前方宣言
前方宣言をインポートするには、objcnames.classesおよびobjcnames.protocolsパッケージを使用します。例えば、library.packageを持つObjective-Cライブラリで宣言されたobjcprotocolName前方宣言をインポートするには、特別な前方宣言パッケージimport objcnames.protocols.objcprotocolNameを使用します。
2つのobjcinteropライブラリを考えてみましょう。1つはobjcnames.protocols.ForwardDeclaredProtocolProtocolを使用し、もう1つは別のパッケージに実際の__実装を持つものです。
// First objcinterop library
#import <Foundation/Foundation.h>
@protocol ForwardDeclaredProtocol;
NSString* consumeProtocol(id<ForwardDeclaredProtocol> s) {
return [NSString stringWithUTF8String:"Protocol"];
}// Second objcinterop library
// Header:
#import <Foundation/Foundation.h>
@protocol ForwardDeclaredProtocol
@end
// Implementation:
@interface ForwardDeclaredProtocolImpl : NSObject <ForwardDeclaredProtocol>
@end
id<ForwardDeclaredProtocol> produceProtocol() {
return [ForwardDeclaredProtocolImpl new];
}2つのライブラリ間でオブジェクトを転送するには、Kotlinコードで明示的なasキャストを使用します。
// Kotlin code:
fun test() {
consumeProtocol(produceProtocol() as objcnames.protocols.ForwardDeclaredProtocolProtocol)
}対応する実クラスからのみ、
objcnames.protocols.ForwardDeclaredProtocolProtocolにキャストできます。 そうでなければ、エラーが発生します。
マッピングされた型間のキャスト
Kotlinコードを記述する際、オブジェクトをKotlin型から同等のSwift/Objective-C型に(またはその逆に)変換する必要がある場合があります。この場合、例えば以下のように通常のKotlinキャストを使用できます。
val nsArray = listOf(1, 2, 3) as NSArray
val string = nsString as String
val nsNumber = 42 as NSNumberサブクラス化
Swift/Objective-CからのKotlinクラスおよびインターフェースのサブクラス化
Kotlinのクラスとインターフェースは、Swift/Objective-Cのクラスとプロトコルによってサブクラス化できます。
KotlinからのSwift/Objective-Cクラスおよびプロトコルのサブクラス化
Swift/Objective-Cのクラスとプロトコルは、Kotlinのfinalクラスでサブクラス化できます。非finalなKotlinクラスがSwift/Objective-C型を継承することはまだサポートされていないため、Swift/Objective-C型を継承する複雑なクラス階層を宣言することはできません。
通常のメソッドは、Kotlinのoverrideキーワードを使用してオーバーライドできます。この場合、オーバーライドするメソッドは、オーバーライドされるメソッドと同じパラメータ名を持つ必要があります。
時にはイニシャライザをオーバーライドする必要がある場合があります。例えば、UIViewControllerをサブクラス化する際などです。Kotlinコンストラクタとしてインポートされたイニシャライザは、@OverrideInitアノテーションが付けられたKotlinコンストラクタによってオーバーライドできます。
class ViewController : UIViewController {
@OverrideInit constructor(coder: NSCoder) : super(coder)
...
}オーバーライドするコンストラクタは、オーバーライドされるコンストラクタと同じパラメータ名と型を持つ必要があります。
競合するKotlinシグネチャを持つ異なるメソッドをオーバーライドするには、クラスに@ObjCSignatureOverrideアノテーションを追加できます。このアノテーションは、Objective-Cクラスから同じ引数型だが異なる引数名を持つ複数の関数が継承される場合に、Kotlinコンパイラに競合するオーバーロードを無視するように指示します。
デフォルトでは、Kotlin/Nativeコンパイラは、非指定Objective-Cイニシャライザをsuper()コンストラクタとして呼び出すことを許可しません。指定イニシャライザがObjective-Cライブラリで適切にマークされていない場合、この動作は不便なことがあります。これらのコンパイラチェックを無効にするには、ライブラリの.defファイルにdisableDesignatedInitializerChecks = trueを追加します。
C機能
ライブラリがunsafeポインタや構造体などのプレーンなC機能を使用する場合の例については、Cとの相互運用を参照してください。
未サポート
Kotlinプログラミング言語の一部の機能は、Objective-CまたはSwiftのそれぞれの機能にまだマッピングされていません。現在、生成されるフレームワークヘッダーで適切に公開されていない機能は次のとおりです。
- インラインクラス(引数は基になるプリミティブ型または
idとしてマッピングされます) - 標準的なKotlinコレクションインターフェース(
List、Map、Set)やその他の特殊クラスを実装するカスタムクラス - Objective-CクラスのKotlinサブクラス
