PromiseKitの使い方 その3
Nov 21, 2017 · iosswift3
SwiftでPromiseを使える様になるPromiseKitの使い方 その3
より実践的な応用パターンの書き方
応用パターン
入れ子にする
Promiseの中身は、非同期処理がキューで詰まっている様なものである。
それで、thenの中でPromiseを返す時に、複数の非同期処理を繋いだPromiseを返すことができる
これにより、ある非同期処理の結果によって次に実行する非同期処理のフローを変更するといった使い方ができる
例えば、hogeメソッドの処理結果がtrueなら非同期処理フローA(A-1→A-2→C)を実行、falseなら非同期処理フローB(B→C)を実行させたい場合は、以下の様に実装できる
firstly {
hoge()
}.then { result: Bool -> Promise<String> in
if result {
return self.hogeA()
} else {
return self.hogeB()
}
}.then { result: String
// 非同期処理C
}.then {
// 以下省略
}
func hogeA() -> Promise<String> {
return firstly {
// 非同期処理 A-1
}.then {
// 非同期処理 A-2
}
}
func hogeB() -> Promise<String> {
return firstly {
// 非同期処理 B
}
}
例の様に、非同期処理のサブルーチン部分をメソッドに切り出しておくとフローが複雑な場合でもみやすくなり、1つのメソッドが巨大になることも防げる
もちろん、hogeBの様にわざわざメソッドに切り出す程でもないぐらいと判断するなら、
firstly {
hoge()
}.then { result: Bool -> Promise<String> in
if result {
return self.hogeA()
} else {
return firstly {
// 非同期処理 B
}
}
}.then { result: String
として、直接入れ子にしても良いが、コールバック地獄が復活する感じなのでおすすめはしない
この時の注意点としては、チェーンにcatchやデータを直接返すthenの様にPromiseを返さないものをつけられないことである。
それでもし、このサブルーチンだけで一旦エラーを処理したい場合(非同期処理フローAの失敗は一旦hogeAの中で処理したい)はrecoverを使うと良い
非同期処理に引数を渡したい場合
Promiseを返すメソッドを作るのに、PromiseKit.wrapは便利だが、引数でデータを渡せないというデメリットがある。かといって、クラスのメンバ変数を使うのはカプセル化が崩れるので望ましくない。そこで、Swiftの関数はファーストクラスであるというのを利用して次の様に書くことができる
func wrapHoge(data: Data) -> Promise<Data> {
let task = { (completion: (Data?, Error?) -> Void) -> Void in
hoge(data: data, completion: completion)
}
return PromiseKit.wrap(task)
}
// wrapしたいメソッド(dataが引数で渡したいデータ)
func hoge(data: Data, completion: (Data?, Error?) -> Void) {
// 非同期処理
}
firstly {
wrapHoge()
}.then { result: Data in
なお、taskの中にhogeメソッドの内容を全て書いてしまうのもあり
非同期処理をスルーしたい場合
例えば、特定の条件の時は非同期処理をまるっと飛ばして(あるいは同期的な処理をして)次の非同期処理に進みたい場合の方法。
非同期処理をせずに次の処理に進むには、Promise(value:)を使う
このコンストラクタは呼び出されると即時に成功扱いとなるPromiseを返す。
引数のvalueには次の処理に渡すデータを指定しなければならない
実際に使う場合は、
firstly {
hoge()
}.then { result: Bool -> Promise<String> in
guard result else { return Promise(value:"") }
return self.hogeA()
}.then { result: String
// 非同期処理C
という様に書けば良い。
この例だとhogeの結果がfalseの場合は、""(空文字)のデータを渡すPromiseを返しているので、非同期処理Cに""が渡されて処理が行われる
なお、次の処理(非同期処理C)がVoidの場合は、引数に()を指定すれば良い
開発環境
- Xcode 8.3.3
- iOS 10.3
- PromiseKit 4.4
