【Kotlin】と【Swift】のCallback実装をまとめてみる

KotlinとSwiftを両方書いていて、Callbackの書き方に迷うことがちょくちょくあるので、備忘録としてまとめます。

KotlinとSwift両方の言葉が混在しており、自分も消化しきれてないところもあるので、文法的に違うとか、ツッコミあったら是非お願いします！

# 環境

* Swift: 4.2
* Kotlin: 1.2.60

# KotlinとSwiftのCallback早見表

Swiftを始めて一番思ったのが、protocol(interface)の無名クラス実装ができないことでした。
extensionを使った継承ができるから不要という考え方なのだろうか :thinking: 

ということで、何ができるか一覧にしました。
まとめてみると、ほとんど同じことができることがわかりました。

| 実装方法 | Kotlin | Swift |
| --- | --- | --- |
| 委譲(Delegateパターン)の継承実装 | ○ <br> interface | ○ <br> protocol |
| 委譲(Delegateパターン)の無名クラス実装 | ○ <br> interface | × |
| 関数型の変数 | ○　<br> lambda  | ○ <br> closure |
| typealias(名前付き関数)の変数 | ○ <br> lambda | ○ <br> closure |


# 委譲(Delegateパターン)の継承実装

kotlinでもswiftでもよく使うやり方だと思います。
interfaceやprotocolを継承して、委譲元に自分自身のinstanceを渡すのが特徴です。

## Kotlin 

kotlinだとOnClickListenerとかでよく使う印象があります。

```kotlin

interface SomeCallback {
    fun doSomething()
}

class Child {
    var callback: SomeCallback? = null

    fun doSomething(){
        callback?.doSomething()
    }
}

class Parent: SomeCallback {
    var child = Child()

    init {
        child.callback = this
    }
    override fun doSomething() {
        // do something
    }
}
```

## Swift

swiftだと、〇〇Deligateというクラスがよく出てくるので、馴染みが深いですね。
callbackがweakになっているのと、protocolがClass-Only Protocolになっているのに注意して下さい。忘れると、メモリリークします。

```swift
protocol SomeCallback: class {
    func doSomething()
}

class Child {
    weak var callback: SomeCallback? = nil
        
    func doSomething(){
        callback?.doSomething()
    }
}

class Parent: SomeCallback {
    var child = Child()
    
    init() {
        child.callback = self
    }
    
    func doSomething() {
        // do something
    }
}
```


# 委譲(Delegateパターン)の無名クラス実装

委譲先のクラスのインスタンスを委譲元のクラスに渡すのが、なんとなく大げさな気がして、kotlinではよく使っていましたが、swiftではできないようです。

## Kotlin

```kotlin
// ChildクラスとSomeCallbackクラスは同上

class Parent {
    var child = Child()

    child.callback = object: SomeCallback {
            override fun doSomething() {
                // do something
            }
        }
}
```

## Swift

**できません。**

できない代わりに、extension毎にprotocolを実装することはできます。これで、コードの見通しはよくなります。
ただ、自分自身のinstanceを渡していることには変わりないので、Child側のcallbackがweakでないと、メモリリークします。

```swift
// ChildクラスとSomeCallbackクラスは同上

class Parent {
    var child = Child()
    
    init() {
        child.callback = self
    }
}

extension Parent: SomeCallback {
    func doSomething() {
        // do something
    }
}
```

# 関数型の変数

関数型の変数を用いることで、interface, protocolを用いるより、ライトな感じでコールバックを実装できます。

## Kotlin

```kotlin
class Child {
    var function: (() -> Unit)? = null

    fun doSomething(){
        function?.invoke()
    }
}

class Parent {
    var child = Child()

    init {
        child.function = {
            // do something
        }
    }
}
```

## Swift

Swiftでは、代入しているClosureが[weak self]になっているのに、注意して下さい。
これも、ないとメモリリークの原因になります。

```swift

class Child {
    var function: (() -> ())? = nil
    
    func doSomething(){
        function?()
    }
}

class Parent {
    var child = Child()
    
    init() {
        child.function = { [weak self] in
            // do something
        }
    }
}

```

# typealias(名前付き関数)の変数

実装内容的にはほぼ**関数型の変数**と同じです。
関数に名前をつけることで、少しわかりやすくなる印象です。

## Kotlin

```kotlin
typealias Alias = () -> Unit

class Child {
    var alias: Alias? = null

    fun doSomething(){
        alias?.invoke()
    }
}

class Parent {
    var child = Child()

    init {
        child.alias = {
            // do something
        }

    }
}

```


## Swift

```swift
typealias Alias = () -> ()

class Child {
    var alias: Alias? = nil
    
    func doSomething(){
        alias?()
    }
}

class Parent {
    var child = Child()
    
    init() {
        child.alias = { [weak self] in
            // do something
        }
    }
}
```

# まとめ

今回はKotlinとSwiftでコールバック実装を書いてみました。

一通り両方で書いてみてKotlinでは循環参照とかそんなに意識しないで書いているなー。ということに気づきました。
swiftはかなり意識して書かないと循環参照が起きてメモリリークを起こすという文献がたくさん出てきたけど、Kotlinは調べて出てこなかったので、ガベージコレクタが優秀なのだと思います。
（デバッグ等できちんと確認はしてないので、間違っていたらごめんなさい。ツッコミお待ちしております！

## 参考

Swiftの循環参照については、こちらを参考にさせていただきました。

- [Swiftの @escaping と weak/unowned の理解](https://qiita.com/ottijp/items/e45b65263c53037af1ee)