Swiftで複数の非同期処理を扱うライブラリAsyncKitを書きました

記事の内容はこちらを参照してください。
https://mishimay.github.io/7df447969a1c38d856d8/
<!--

以前書いた記事「[Swiftで複数の非同期処理を並列実行させて、すべてが終わったらコールバックを受け取る関数](http://qiita.com/mishimay/items/e3f393c26661c1f7850c)」の反響が思っていたよりあったのでもう少し改良してみることにしました。

そうしたところ、不便だった点が解消され実用に足るものになったと思いますのでライブラリにして公開してみました。

以前の記事では `parallel` 関数だけだったのですが、それだけではさみしいので `series`と `waterfall` 関数も追加しています。


# なにができるのか？
Web API リクエストなどの非同期処理を複数同時に行い、すべてが終わったらそれぞれの非同期処理の結果を使って別の処理をさせたい、ということはよくあると思います。

しかしこれを実装するためには、すべての非同期処理が終わったことを判定する変数を用意したり、GCDを使用したりする必要があり、なかなかきれいにコードを書くことができません。

このライブラリでは、そういった複数の非同期処理をまとめて実行したいときにクリーンで簡潔なコードが書けるような便利な関数を提供します。

特徴としては

- 複数の非同期処理の結果を一か所で受け取れる
- 非同期処理のどれかでエラーが発生したらすぐエラーハンドリングできる (複数の非同期処理でエラーが発生してもエラーハンドリングのコードは1度だけ実行される)

といったことが挙げられます。

ちなみに、このライブラリはJavaScriptの [async](https://github.com/caolan/async) という有名なライブラリに影響を受けています。
関数名や使い方は [async](https://github.com/caolan/async) に準拠しています。


# AsyncKit
https://github.com/mishimay/AsyncKit

コード
https://github.com/mishimay/AsyncKit/blob/master/Pod/Classes/AsyncKit.swift

## インストール
CocoaPodsに登録されています。

```ruby
use_frameworks!
pod "AsyncKit"
```

## 環境
Swift 2.1


# 簡単なコード例

```swift
let async = AsyncKit<String, NSError>()

// 並列実行
async.parallel(
    [
        { done in done(.Success("1")) },
        { done in done(.Success("2")) }
    ]) { result in
        print(result) // -> Success(["1", "2"])
}

// 直列実行
async.series(
    [
        { done in done(.Success("1")) },
        { done in done(.Success("2")) }
    ]) { result in
        print(result) // -> Success(["1", "2"])
}

// 直列実行 && 非同期処理の結果を次の非同期処理へ渡す
async.waterfall("0"
    [
        { argument, done in done(.Success("1")) },
        { argument, done in done(.Success("2")) }
    ]) { result in
        print(result) // -> Success("2")
}
```


# 基本的な使い方


1. AsyncKitをインスタンス化
  - その際、非同期処理の**成功時**に結果として渡すオブジェクトの型と**失敗時**に結果として渡すオブジェクトの型を指定します。
  - e.g.

    ```swift
    let async = AsyncKit<String, NSError>()
    ```

1. 非同期処理の準備
  - 非同期処理をクロージャとして用意します。
      - クロージャの型
          - parallelとseries: `AsyncKit.Process`
          - waterfall: `AsyncKit.ProcessWithArgument`
  - 上記の「簡単なコード例」のように、AsyncKitの関数を呼ぶ際に配列の中に直接クロージャを書いても構いません。
  - 非同期処理の最後に処理が成功した/失敗したことを伝えるため、引数で受け取ったクロージャを呼びます。
      - クロージャの引数にはenum `Result` の値 (`.Success` か `.Failure`) を渡します。
      - enumの associated value として、非同期処理の結果として得られたオブジェクトを指定します。 
  - e.g.

    ```swift
    let process1: AsyncKit<String, NSError>.Process = { done in
        request() { object, error in
            if error == nil {
                done(.Success(object))
            } else {
                done(.Failure(error))
            }
        }
    }
    ```

1. AsyncKitの関数に非同期処理の配列を渡し、結果を受け取る
  - 結果はenum `Result` として返され、成功 (`.Success`) か失敗 (`.Failure`) のどちらかの値になっています。
      - enumの associated value には、`.Success`時には成功時オブジェクトの配列が、`.Failure`時には失敗時オブジェクトが入っています。
  - e.g.

    ```swift
    async.parallel([process1, process2]) { result in
        switch result {
        case .Success(let objects):
            print(objects)
        case .Failure(let error):
            print(error)
        }
    }
    ```


# それぞれの関数の説明

## parallel
非同期処理を**並列実行**します。
すべての非同期処理が成功したら `.Success` とともに完了クロージャが呼ばれます。
`.Success` の associated value は、非同期処理の結果のオブジェクトが非同期処理と同じ順番で入った配列になっています。
いずれかの非同期処理が失敗したら `.Failure` とともに完了クロージャが呼ばれます。
複数の非同期処理が失敗しても完了クロージャが呼ばれるのは1度だけです。

## series
非同期処理を**直列実行**します。
すべての非同期処理が成功したら `.Success` とともに完了クロージャが呼ばれます。
いずれかの非同期処理が失敗したら `.Failure` とともに完了クロージャが呼ばれ、それ以降の非同期処理は実行されません。

## waterfall
非同期処理を**直列実行**し、かつ**非同期処理の結果を次の非同期処理へ渡し**ます。
すべての非同期処理が成功したら `.Success` とともに完了クロージャが呼ばれます。
いずれかの非同期処理が失敗したら `.Failure` とともに完了クロージャが呼ばれ、それ以降の非同期処理は実行されません。


# PromiseKitやRxSwiftとの違い

非同期処理を扱うライブラリにはいろいろ種類があり、有名所だとPromiseKitやRxSwiftがあります。

しかしそれらのライブラリは概念が少し複雑で、一度理解すれば便利に使えるのですが最初はとっつきにくい印象があると思います。
また、ライブラリの規模が大きく、ちょっとしたことで使うには少し気後れしてしまいます。

それに対して、このAsyncKitは実態はswiftファイル1つだけなので軽量ですし、やっていることが明瞭なのでなにをするものなのか理解しやすいと思います。


# おわりに

以前JavaScriptのライブラリ [async](https://github.com/caolan/async) を触ったとき、その過不足のない調度良い感じ、手に馴染むその手触り感が好きでした。

それをSwiftでも使いたいなと思ったのが始まりです。

[async](https://github.com/caolan/async) を使ったことがある方ならすぐに使いこなせると思います。

Swiftの強力な型システムによってより堅牢に、扱いやすくなっていますのでぜひ試してみてください。



-->