PromiseKit 6 にアップデートしたらいろいろ変わってたメモ

# PromiseKit6が出てた

https://github.com/mxcl/PromiseKit
https://promisekit.org/news/2018/02/PromiseKit-6.0-Released/

まだ絶賛PromiseKit4使用中だったので、バージョンを上げましょうという話になった。
ご丁寧に上記URLでPromiseKit4からの変更について書かれている。

本記事では、バージョンアップのmigrationの際に主に変更があった部分のメモだけ載せるので、詳しくは上記を参照してください。

何か間違いあればご指摘お願いします :bow: 

## initializerが変わったので対応する

今まで

```swift
Promise { fulfill, reject in
    if ... {
        fulfill(data)
    } else {
        reject(error)
    }
}
```

新しいやつ

```swift
Promise { resolver in
    if ... {
        resolver.fulfill(data)
    } else {
        resolver.reject(error)
    }
    // resolver.resolve(data, error) でもOK
}
```

resolver (公式ではseal) が引数として渡されるようになったのね。中身はそんなに変わってないけど、 `resolver.resolve` で一気に渡せるようにもなってる。

## `then`が３つに別れたので対応する

今まで`then`で一括りにされていたのが、次の３つに分解された。
元の`then`は次の3つがあった。

```swift
then(execute: Results<U>) -> Promise<U>
then(execute: Results<U>) -> AnyPromise
then(execute: Results<U>) -> U
```

AnyPromiseは置いておくとして、`then`ひとつでPromiseを返すものとその値を返すものがあった。
また、多くの場合で何も値を返したくないこともあり、明示的に `Promise<U> -> Void` と書いてやることでコンパイルエラーを回避する、ということをやっていたりした。(私だけだったら悲しい)
これらをわかりやすくするために次の３つができたっぽい。

- then
- done
- map

### `then` (新しい方)
Promiseを受け取ってPromiseを返すときに使う。今までどおり。

```swift
somePromise.then { obj -> Promise<U> in
    doSomething(obj)
    return getSomePromise()
}.then ...
```

### `done`
Promiseを受け取って何も返却値がないときに使う。だいたいこれを使うことが多い。

```swift
promise.done { obj in
    some(obj)
}
```

### map

Promiseを受け取って中のvalueなどPromiseでない値を返すときに使う。

```swift
promise.map { obj -> U in
    value = some(obj) // valueは非Promise
    return value
}
```

### その他の便利なやつ

他にも、上記の３つ+αなもののエイリアス的なメソッドが増えていた。

#### compactMap

`map`のoptional unwrap付きバージョン。`nil`だと`catch`に入る。

```swift
somePromise.compactMap { data in
    UIImage(data: data)
}.done { image in
    imageView.image = image
}.catch {
    ...
}
```

#### get

`done`と同じで明示的にreturnしないが、与えられたものと同じ値を返す。

```swift
somePromise.get { data in
    setup1(data)
}.done { data in
    setup2(data)   
}
```

#### tap

値を `Result<T>` でラップした値を受け取る。`catch`使えばいいんじゃないかと思うけど、何か用途があるんだろうか。

## `always`なくなって`ensure`になった

名前変わっただけ。

## `catch`がPromiseを返さなくなった

地味にやっかいなやつ。
`catch`がPromiseを返さなくなったので、このあとに処理を続けられなくなった。
`ensure`もダメ。
しかしまぁ、エラーのあとにやりたい処理があるでしょ、という場合のために `finally` が追加された。

というわけで、`catch`のあとには`finally`を使う。

```swift
somePromise.done { data in
    setData(data)
}.catch { e in
    handleError(e)
}.finally {
    finish()
}
```

Promiseを返すメソッドの最後がcatchになっていた場合ややこしい気がする。やってみて追記する。

## 新しい型 `Guarantee<T>` ができたので使えそうなら使っていく

failしないPromiseとして`Guarantee<T>`ができた。
`catch`が書けなくなるので、エラーになることのない処理はこっちになる。わかりやすい例のは`after`。

```swift
after(seconds: 1.0).done {
    startAnimation()
} // .catchは書けない
```

エラー有り無しを制御しやすくて良い。UIKitのextensionにあった `UIView.animate` 系も `Guarantee<Bool>` を返すようになっている(下記参照)。

## UIViewのアニメーション

UIKitのextensionも同様に更新されていて、例えばアニメーションの書き方が少し変わっている。
https://github.com/PromiseKit/UIKit

大きな違いは、`Promise<Bool>` ではなく `Guarantee<Bool>` を返すようになっている点。
catchを書けなくなったので良い。

今まで

```swift
UIView.promise(animateWithDuration: 0.2, animation: {
    someMove()
}).then { 
    ... 
}
```

新しい

```swift
UIView.animate(.promise, duration: 0.5, options: .curveLinear) {
    someMove()
}.then { _ -> Guarantee<Bool> in
    return UIView.animate(.promise, duration: 1.0, delay: 1.0, options: .curveEaseOut) {
        anotherMove()
    }
}.then {
    ...
```



## 調べる予定

時間切れなのでこのへんにしつつ、他にもなにかでてきたら調べて追記したい

例えば、
~~`UIView.promise`にwarning消すために全部catch書くのが面倒~~ `UIView.animate` も変わってたので追記済み。