Swiftでは非同期処理が多用されます。非同期処理の結果はコールバック方式になっているので、非同期処理が続くとネストがどんどん深くなってしまいます。そこでJavaScriptでは昔からPromiseという方式が使われてきました。
iOSではPromiseKitなどが知られていますが、この記事では高機能なPromiseライブラリであるHydraとiOS SDKを組み合わせる方法を紹介します。
Hydraのインストール
HydraはCocoaPodsなどでインストールできます。
# use_frameworks! pod 'HydraAsync'
Hydraの使い方
Hydraはまず使うViewController上でインポートします。
import Hydra
例えばファイルストアへアップロードする処理の場合、次のように関数を作ります。
func uploadPhoto(file: NCMBFile) -> Promise<NCMBFile> { return Promise<NCMBFile>(in: .background, { resolve, reject, _ in file.saveInBackground({(error) in if error != nil { // 保存失敗時の処理 reject(error!) } else { // 保存成功時の処理 resolve(file) } }) }) }
そして、これを使う方は以下のように書きます。 in: .main
を書いた後、resolveやrejectで受け取る引数を記述します。
let file = NCMBFile.file(withName: fileName, data: photoData) as! NCMBFile self.uploadPhoto(file: file).then(in: .main, {file in print("アップロード完了") print(file) }) .catch(in: .main, { error in print(error) })
async/awaitも
さらにPromiseの場合はチェーンでつないだ時に、前の結果を見られない(別な変数をスコープ外で定義しておく必要がある)のが不便です。そこでJavaScript界隈で使われているのがasync/awaitになります。Hydraでも同様に操作が可能です。
先ほどの処理をasync/awaitで書き直したものです。asyncというグローバル関数が定義されており、それを使うことで非同期処理をawaitで囲んで書けるようになります。最後にreturnすることでthen処理に繋ぐこともできます。
async { _ -> NCMBFile in let result = try! await(self.uploadPhoto(file: file)) return result }.then({fileResult in print(fileResult) })
次の処理に繋げない場合でも async 関数を実行するために then は必要です。特に引数が不要な場合は次のように書けます。
async { _ -> Void in let result = try! await(self.uploadPhoto(file: file)) print(result); return }.then({_ in })
まとめ
Hydraを使うことで、NCMBのように非同期処理の多いSDKでも容易に扱えるようになります。コールバックやPromiseで苦しんだ経験のある方はHydraを使ってみてください。
malcommac/Hydra: Lightweight full-featured Promises, Async & Await Library in Swift