Alamofireの処理遅延をSwift-Promisesで実装する [Swift 1.1]

## 問題点

SwiftでのiOSアプリ開発において、
Alamofire[*1](https://github.com/Alamofire/Alamofire)とか通信系の関数を使用すると、
コールバックの中身の実行が通信終了を
待たずして別の処理が走ってしまう。

意図した処理が実装できず、例えば
下図のようにAPIを叩いた結果が
テーブルに表示されない悲しい事例も見られる[*2](http://qiita.com/tsumekoara/items/7293c54762afeeb10ed5#comment-d0b6df49974994cfdb52)。

![Screen_Shot_2015-05-30_at_19.54.44.png](https://qiita-image-store.s3.amazonaws.com/0/19990/095aec55-56ac-89d3-d84b-2b036531de37.png)

このような事態に対応するべく、
javascript/jQuery界隈では
Deferredオブジェクトという
状態監視インスタンスの導入が利用されている。

今回はこのDeferredオブジェクトを用いて
遅延処理の実装を行う。

## ゴール

Alamofireの通信終了後に
意図した処理を実行する。

## 方針

Deferredオブジェクトを使う。
Deferredオブジェクトは処理が
進行中／完了後／異常終了のどの状態に
あるのかを監視するオブジェクトとなっている。
通信が終了したタイミングで
状態を"完了後"とすれば、
その後に続けたい処理を書くことで
コールバックを使いながらも{通信}→{意図した処理}の
順で実装できる。

javascript, 特にjQueryではajaxとともに
よく使われるオブジェクトである。

## 実装内容

RokkinCat/Swift-Promises[*3](https://github.com/RokkinCat/Swift-Promises)にあった
Classesフォルダ以下の、Promise.swiftを
アプリソースコードに追加。

Promises in Swift[*4](https://medium.com/@robringham/promises-in-swift-66f377c3e403)の特に下記のcode1を参考にしながら
`func callAPI() -> Promise`という
関数を実装した。

```swift:code1
func uploadFile() -> Promise {
  let p = Promise.defer()
  dispatch_async(
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
    {
        let success = self.actualFileUpload()
        if !success {
            p.reject()
        }
        dispatch_async(dispatch_get_main_queue(), {
            p.resolve()()
        })
    })
  return p
}
```

```swift:MyPageViewController.swift
...
    let deferred = Deferred()
...
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        callAPI().then{(value) -> () in
            self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
            self.tableView.reloadData()
        }
    }

    func callAPI() -> Promise{
        let promise = deferred.promise
        Alamofire.request(CRUDRouter.Read(routerName: "users/1/favorites", id: 0))
            .responseJSON { (_, _, JSON, _) in
                var arr : NSArray = JSON!["comment"]!! as NSArray
                for a in arr{
                    self.items.append(a["comment"]!! as String)
                }
                self.deferred.resolve("end API calling")
        }
        return promise
    }
```

## 実装結果

下記のようなテーブルに
文章の追加された画面が、
画面表示後0.2秒程度で表示されるようになった。
Deferredを実装していない時には、
タブを行き来して2回目に表示したときに
初めて表示されていた。
(TableViewの実装方法については
ここでは割愛します。)

![Screen_Shot_2015-05-30_at_20.11.20.png](https://qiita-image-store.s3.amazonaws.com/0/19990/90b35b81-6dbe-6056-cdaf-2c35abdf88f4.png)

これにより、Deferredを使うことで
正しく通信→処理の順に
実装できることが確かめられた。

表示されているテキストは自前の
バックエンドに対してHTTP Requestを
飛ばした結果となっている。

## まとめ

本記事ではDeferredを用いた処理遅延を実装してAlamofireの通信後に意図した処理を実行させた。
むっちゃ頑張った。
SwiftとJavascriptは似ているのではないかという気もしてきた。
JSONのAPIをコールする実装を紹介する記事[*5]
(http://qiita.com/yonell/items/c5432207868fa2d5cfc9)は
あったが、Alamofireの方が
API周りを簡潔に書けるため、こちらのほうが
コストの低い実装となると思う。
また、他のDeferredオブジェクトの実装[*6](http://qiita.com/xxxAIRINxxx/items/ba56c9bf51dde79157a
4)もありえたが、
今回はすぐに見つかったもので実装した。

## 参考文献

1. [Alamofire/Alamofire](https://github.com/Alamofire/Alamofire)
2. [[Swift 1.1] swiftで api を叩いて、JSONをパースして、表示させる方法 (xcodeは6.1, iOSは8.1)](http://qiita.com/tsumekoara/items/7293c54762afeeb10ed5#comment-d0b6df49974994cfdb52)
3. [RokkinCat/Swift-Promises](https://github.com/RokkinCat/Swift-Promises)
4. [Promises in Swift](https://medium.com/@robringham/promises-in-swift-66f377c3e403)
5. [[Swift]APIで取得したJSONをswiftyJSONでパースして、天気情報をUITableViewで表示。お天気アプリを作ってみる。](http://qiita.com/yonell/items/c5432207868fa2d5cfc9)
6. [【iOS】 コールバック地獄から脱出する為のライブラリ一覧](http://qiita.com/xxxAIRINxxx/items/ba56c9bf51dde79157a
4)
7. [SwiftでiOS開発：RSSリーダー](http://blog.andgenie.jp/articles/291)