Swift to Kotlinチートシート

SwiftをKotlinに書き換えるにあたってのチートシート。

# コード変換
[angelolloqui/SwiftKotlin](https://github.com/angelolloqui/SwiftKotlin)
このツールでSwiftからKotlinへの静的なコード変換ができる。

[こちらのページ](https://github.com/angelolloqui/SwiftKotlin/releases)から直近リリースの変換ツール（SwiftKotlinApp.2017-12-10.20-14-06.zipなど）をダウンロードできる

便利なツールだが完璧な変換ができるわけではなく、ざっと確認したところ以下の問題があった。

* class var、class funcが上手く変換されない（staticは大丈夫）
* enum内のfuncなどが変換されない
* タプルが上手く変換されない（Kotlinにはそもそもタプルがない）
* deferブロックが上手く変換されない
* case文にenumをフル修飾で書く（ case Animal.dog: のような形 ）とエラーになった

このツールでベースのKotlinコードを作って、細部を手直ししていく。

# UIViewControllerのviewをAndroidの何に置き換えるか

* Activity
* Fragment
* ConstraintLayout、FrameLayoutなど

上記のような候補が考えられたが、今のところFragmentが一番妥当という結論。
（ノウハウはあまりないので後で覆る可能性はあり）

2018/5/20追記: 覆った。Fragmentは使わずシンプルなViewGroupを持つUIViewControllerを作るのがベスト。設計に関する詳細は以下に記載。
[iOSのソースをなるべくそのままAndroidに移植する方法](https://qiita.com/alt_yamamoto/items/acabbc5f1e891bc6d115)

Activityが複数無ければ各ActivityのlaunchModeなどを考える必要がなくなり、データ連携もiOSと似せることができる。
ただし、onConfigurationChangedなどは一括でハンドルして、画面毎に処理を分けてやる必要があったりパフォーマンスの面で検証が必要。

# optional
使い方はSwiftと似てるが違いもある。

### Nullの置き換え

```Swift:Swift
foo ?? "-"
```
```Kotlin:Kotlin
foo ?: "-"
```

### 宣言時に値を入れられないがOptionalとして扱いたくない場合

```Swift:Swift
var foo: String!
```
```Kotlin:Kotlin
lateinit var foo: String
```

### オプショナルチェイン
Swiftと違ってKotlinは?を毎回書く必要がある

```Swift:Swift
a?.b.c.d.e
```
```Kotlin:Kotlin
a?.b?.c?.d?.e
```

# コレクション
https://qiita.com/opengl-8080/items/36351dca891b6d9c9687

List、Map、Setがある。
値の追加などの変更操作をする場合は、MutableListなどMutableをつけたクラスを使う必要がある。

```Kotlin:Kotlin
class Foo {
   // 下記2行はどちらも同じ意味
   val list1: MutableList<String> = mutableListOf()
   val list2 = mutableListOf<String>()
}
```

# List

```Swift:Swift
let list = ["1", "2", "3"]

for str in list {
    print(str)
}

list.forEach {
    print($0)
}

// インデックスを使う場合
list.enumerated().forEach {
    print("\($0.offset): \($0.element)")
}
```

```Kotlin:Kotlin
val list = listOf("1", "2", "3")

for (str in list) {
    Log.d("TEST", str)
}

list.forEach {
    Log.d("TEST", it)
}

// インデックスを使う場合
list.forEachIndexed { index, str ->
    Log.d("TEST", "${index}: ${str}")
}
```

# Map

KeyValue指定のforEachはAPILevel24からしか使えない。

```Kotlin:Kotlin
tasks.forEach { key, value ->  }
```

APILevel24未満の場合は entry 指定のものを使う

```Kotlin
tasks.forEach { entry ->  }
```

# static 変数、関数はない
Companion Objectを使って同じようなことが実現できる

```Kotlin:Kotlin
class Hoge {
    companion object {
        fun foo() {}
    }
}
Hoge.foo()
```



# シングルトンの作り方
classの代わりにobjectキーワードを使うとシングルトンになる。シングルトンにはクラス名（オブジェクト名？）+ドットでアクセスできる

```Kotlin:Kotlin
object Hoge {
    fun method() {}
}
Hoge.method()
```

# if let の書き方
if 文でnullチェックすれば、ifブロックの中では not-null として扱える。
（チェックした内容に応じて自動castされる、smart cast という機能）

```Kotlin:Kotlin
fun boo(foo: Foo?) {
    if (foo != null) {
        foo.bar() // not-null なので ? をつけず使える
    }
}
```

ただし、propertyなど、nullチェックするスコープの外で値が変わり得る場合は、スコープ内で変数を再定義してnullチェックしないと smart castされない。

```Kotlin:Kotlin
class Sample {
   var foo: String? = null
   fun boo() {
      val foo = foo // nullチェック前にローカルスコープで再定義しないとsmart castされない
      if (foo != null) {
         foo.bar()
      }
   }
}

```

let を使って以下のようにも書けるが、多くの場合は上記の smart cast を使うことを推奨する。

```Kotlin:Kotlin
val name: String? = "John Doe"
name?.let {
   print("${it}")
}
```
※it はSwiftの $0 のような役割

また、letは?を書き忘れると null でも実行されてしまい、特にコンパイルエラーも出ないという罠があり危険。

# 引数のラベルはつけなくても良い

```Kotlin:Kotlin
fun foo(arg: String) {}
foo(arg = "Hello")
foo("Hello")
```
引数ラベル（上記の例ではarg）は書いても書かなくても良い。

# クラスとコンストラクターの書き方（継承など）
長いので[こちら](https://qiita.com/yamamoto_keita/items/f5df6434e122859f2d65)にまとめた。

# val は Swiftの let とは意味が異なる
val は immutable ではなく readonly を表す。
Swiftの場合 let 宣言した Array は値の追加などをできないが、val 宣言した List は値の追加などができる。
Listに対して += で値を加えたい場合、val で宣言しないと演算子の解釈が２通り発生してコンパイルエラーになる。

# MutableCollection(MutableListなど)の += の使い方
```Kotlin:Kotlin
val list = mutableListOf<String>()
list += "a"
```
MutableCollection は += で値を追加できるが、その場合 val で宣言する必要がある。
var で宣言すると、+ 部分が別のオペレーターとも判断できるのでコンパイルエラーになる。

# willSet、didSet

```Swift:Swift
var foo: Int = 0 {
    willSet {
        print("willSet \(foo) to \(newValue)")
    }
    didSet {
    	print("didSet \(foo)")
    }
}
```

```Kotlin:Kotlin
var foo: Int = 0
    set(value) {
        Log.d("tag", "willSet ${field} to ${value}");
        field = value
        Log.d("tag", "didSet ${value}");
    }
```

# Range

### 1以上10以下（10も含む）の例
Kotlinはドットが一つ少ない

```Swift:Swift
let range = 1...10 
```

```Kotlin:Kotlin
val range = 1..10 
```

### 1以上10未満（10は含まない）の例
Kotlinはドットではなく `until` を使う。

```Swift:Swift
let range = 1..<10 
```

```Kotlin:Kotlin
val range = 1 until 10 
```

### その他
閉じないRangeに該当する書き方はKotlinにはなさそう。

```Swift:Swift
let range = 1...
```

# DataBinding
Android Studio3.0.1での設定。
DataBindingを使うにはbuild.gradleに以下の設定が必要。

```
apply plugin: 'kotlin-kapt'
android {
    dataBinding {
        enabled = true
    }
}
dependencies {
    kapt 'com.android.databinding:compiler:3.0.0-alpha5'
}
```
ただしこの設定だけではDataBindingのクラスが自動更新されない（Rebuild Projectしないと更新されない）問題があり、現在調査中。
また、このビルド設定でObservablePropertyで変数監視するとエラーになる。
追記：AndroidStudio3.1ではdependenciesのkaptの記載が不要になるとの[情報あり](https://medium.com/@star_zero/databinding%E3%81%AEkapt%E3%82%92%E6%9B%B8%E3%81%8B%E3%81%AA%E3%81%8F%E3%81%A6%E3%82%82%E8%89%AF%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F-3634a3ede080)

以下も必要との記載をいくつか見かけたが、なくても動いてる。
（むしろ最近のAndroidStudioでは記載するとエラーになる？）

```
kapt {
    generateStubs = true
}
```

# ラムダ式の return は親のreturnになってしまう場合がある

Iterable<T>.map などに指定するラムダ式は、値を帰す場合もreturnは記載せず、以下のような形で書く。

```Kotlin
listOf<String>().map { it }
```
mapはinline functionのため、以下のようにreturnを書くと呼び出し元のfunctionにコード展開され、呼び出し元がreturnされてしまう。

```Kotlin
listOf<String>().map { return it }
```

return を書きたい場合は、以下の @map のようにラベルを付けて書くことができる。

```Kotlin
listOf<String>().map { return@map it }
```

# 16進数表記はLong
0x表記で16進数で数値を書けるが、型はIntじゃなくLongになるので適宜変換が必要。

```
ColorDrawable(0xFFFF6666.toInt())
```

# Extensionにインターフェースはかませない
Swiftの以下のような書き方はKotlinではできなさそう。
何か代わりがあればいいが。

```Swift:Swift
extension UIViewController: UITableViewDelegate {
}
```

# 演算子のオーバーロード
まとめると演算子には英名がついてるので、その名前でfunctionを定義してやればよい。
演算子を定義する場合、funの前にoperator修飾子をつける必要がある。

```Kotlin:Kotlin
class Foo(num: Int) {
    val num = num
    operator fun plus(other: Foo): Int {
        return Foo(num + other.num)
    }
}
```

```
val result = Foo(1) + Foo(2)

```

詳しくはこちら
https://qiita.com/KokiEnomoto/items/2fedf864ff0710927b98

# raw string
改行、バックスラッシュ、ダブルコーテーションなどをエスケープしなくて良い。

```Kotlin:Kotlin
val text = """
    for (c in "foo")
        print(c)
"""
```

# Genericsについて

長いので[こちら](https://qiita.com/yamamoto_keita/items/9ff0a7d9723b2c0171a0)に切り出した。

# Reflectionについて

長くなりそうなので[こちら](https://qiita.com/yamamoto_keita/items/123fb83a94327bab8359)に切り出した。


# enumの継承
enum classは継承ができないが、sealed class は継承ができる。

```Kotlin:Kotlin
sealed class HttpTaskError: Exception() {
    object NETWORK: HttpTaskError()
    object STATUS_CODE: HttpTaskError()
    object PARSE: HttpTaskError()
    object INVALID_RESPONSE: HttpTaskError()
}
```

# enumに値を持たせる

```Kotlin:Kotlin
enum class Status(val code: String) {
   success("0"),
   fail("1")
}
```

複数のenum classで同じプロパティやファンクションをもたせたい場合、上記のsealed classでも実現できるが、interfaceの方が手っ取り早い。

```Kotlin:Kotlin
interface TypeCode {
    val code: String
}

enum class Status(override val code: String): TypeCode {
   success("0"),
   fail("1")
}

enum class Category(override val code: String): TypeCode {
   foo("0"),
   bar("1")
}

// クラスとコード値を指定して enum を取得する
inline fun <reified T> enumValue(type: KClass<T>, code: String?) : T? where T : Enum<T>,
 T: TypeCode {
    return enumValues<T>().firstOrNull { it.code == code }
}

```

# メンバーファンクションへの参照
this::ファンクション名 の形でメンバーファンクションへの参照を取得できる。

```Kotlin:Kotlin
class Foo {
    val piyo: ()->Unit = this::hoge
    fun hoge() {}
}
```

# メソッド１つの無名クラスの省略記法（SAM変換）
メソッドが１つだけの interface は無名クラスを省略形で書ける。
SAM(single abstract method)変換という。

```Kotlin:Kotlin
// 省略前
button.setOnClickListener(object: View.OnClickListener {
   override fun onClick(view: View?) {
      // クリック処理
   }
})
```

```
// 省略後
button.setOnClickListener { 
   // クリック処理
}
```

ただし、この機能はJavaで定義されたinterfaceでしか使えないという中途半端な実装状態。
Kotlinのinterfaceも対応されることが望まれる。

# 複数型の宣言

```Swift:Swift
extension UITableView {

    // 引数のdelegate は UITableViewDelegate かつ UITableViewDataSource
    func setup(delegate: UITableViewDelegate & UITableViewDataSource) {
        self.delegate = delegate
        self.dataSource = delegate
    }
}
```

Kotlinの場合どう書く？

# guard let

```Swift:Swift
guard let bar = bar else {
   return
}
```

```Kotlin:Kotlin
val bar = bar ?: return
```

# クラスオブジェクトの取得

Swiftは`クラス名.self`でクラスオブジェクトを取得できるが、Kotlinは`クラス名::class`でクラスオブジェクト（KClass）を取得する。

```Swift:Swift
class Foo {}

func handleClass(class: AnyClass) {}

func run() {
    handleClass(class: Foo.self)
}    
```

```Kotlin:Kotlin
class Foo {}

fun handleClass(klass: KClass<*>) {}

fun run() {
    handleClass(klass = Foo::class)
}   
```