ReSwift Vol2

前回(Vol1)はこちら
http://qiita.com/nakadoribooks/items/c5f53071abdfafd47d4f

javascript実装はこちら
http://qiita.com/nakadoribooks/items/f7f48197d6d5723a96d5

成果物
https://github.com/nakadoribooks/CalilClient-ios/releases/tag/vol2

# ActionCreator リファクタリング

- ActionCreator 内でのDispatchしない

## ライブラリ取り込み

```ruby:Podfile
use_frameworks!
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'

target 'CalilClient' do
  pod 'ReSwift'
  pod "PromiseKit", "~> 4.0"
  pod 'PromiseKit/Alamofire' 
end
```

PromiseKitを使います
https://github.com/mxcl/PromiseKit

## ActionCreator

```swift:ActionCreator.swift
static func loadLibraries(prefName:String="秋田県")-> Promise<Action>{
        
    return Promise { fulfill, reject in
        
        let parameters: Parameters = ["appkey": Config.API_KEY, "pref":prefName, "format":"json", "callback":""]
        Alamofire.request(Config.API_LIBRARY, parameters: parameters).responseJSON().then { responseAny -> Void in
            
            guard let json = responseAny as? [NSDictionary] else{
                // 〜 略 〜
                let failAction = LibraryListFailLoadAction()
                fulfill(failAction)
                return
            }
            
            print("ok json")
            let results = Library.createList(list: json)
            let loadedAction = LibraryListLoadedAction(libraryList: results)
            fulfill(loadedAction)
        }.catch { error in
            let failAction = LibraryListFailLoadAction()
            fulfill(failAction)
        }
    }
}

static func loadLibrariesAction()->Action{
    return LibraryListLoadAction()
}

```


### 変更前 

```
// ActionCreator interface
static func loadLibraries(prefName:String="秋田県")->Action

// 使う側 (View)
let loadAction = ActionCreator.loadLibraries()
mainStore.dispatch(loadAction)

```

### 変更後

```

// ActionCreator interface
static func loadLibraries(prefName:String="秋田県")-> Promise<Action>
static func loadLibrariesAction()->Action

// 使う側 (View)
ActionCreator.loadLibraries().then { (action) -> Void in
    mainStore.dispatch(action)
}
let loadAction = ActionCreator.loadLibrariesAction()
mainStore.dispatch(loadAction)

```

たぶんこっちの方が好ましい。


# ※ 追記 AsyncActionCreator 使用バージョン

Webの方
http://qiita.com/nakadoribooks/items/f7f48197d6d5723a96d5
で redux-thunk のオススメコメントいただいたので、こっちもインタフェース揃える。

AsyncActionCreator
Reswiftの中に入ってる。
こいつが dispatch　に渡せる

```
typealias AsyncActionCreator = (
    _ state: State,
    _ store: Store,
    _ actionCreatorCallback: @escaping ((ActionCreator) -> Void)
) -> Void

mainStore.dispatch(AsyncActionCreator)
```

成果物
https://github.com/nakadoribooks/CalilClient-ios/releases/tag/vol2.5

## 準備

特になし。

## ActionCreator

```swift:ActionCreator.swift
import ReSwift
import Alamofire
import PromiseKit

public enum ActionCreatorError: Error {
    case unknown
    case json
}

struct ActionCreator{
    
    static func loadLibraries(prefName:String="秋田県")->Store<AppState>.AsyncActionCreator {
        return { (state, store, callback) in
            _loadLibraries(prefName: prefName).then(execute: { (action) -> Void in
                callback({ (_, _) -> Action? in action })
            }).catch(execute: { (error) in
                let failAction = LibraryListFailLoadAction()
                callback({ (_, _) -> Action? in failAction })
            })
        }
    }
    
    static func _loadLibraries(prefName:String="秋田県")-> Promise<Action>{
        
        return Promise { fulfill, reject in
            
            let parameters: Parameters = ["appkey": Config.API_KEY, "pref":prefName, "format":"json", "callback":""]
            
            Alamofire.request(Config.API_LIBRARY, parameters: parameters).responseJSON().then { responseAny -> Void in
                
                guard let json = responseAny as? [NSDictionary] else{
                    print("fail json")
                    
                    reject(ActionCreatorError.json)
                    return
                }
                
                print("ok json")
                let results = Library.createList(list: json)
                let loadedAction = LibraryListLoadedAction(libraryList: results)
                
                // 時間かかっているてい
                DispatchQueue.global(qos: .default).async {
                    Thread.sleep(forTimeInterval: 1)
                    DispatchQueue.main.async {
                        fulfill(loadedAction)
                    }
                }
                
            }.catch { error in
                reject(ActionCreatorError.unknown)
            }
            
        }
        
    }
    
    static func loadLibrariesAction()->Action{
        return LibraryListLoadAction()
    }
    
}
```


### 変更前 

```

// ActionCreator interface
static func loadLibraries(prefName:String="秋田県")-> Promise<Action>
static func loadLibrariesAction()->Action

// 使う側 (View)
ActionCreator.loadLibraries().then { (action) -> Void in
    mainStore.dispatch(action)
}
let loadAction = ActionCreator.loadLibrariesAction()
mainStore.dispatch(loadAction)

```

### 変更後

```
// ActionCreator interface
static func loadLibraries(prefName:String="秋田県")->Store<AppState>.AsyncActionCreator
static func loadLibrariesAction()->Action

// 使う側 (View)
mainStore.dispatch(ActionCreator.loadLibraries())
mainStore.dispatch(ActionCreator.loadLibrariesAction())

```

なるほど。