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