0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

NCMBのSwift SDKにおける非同期/同期メソッドの使い分け

Posted at

NCMBの操作はREST APIを介して行います。ネットワーク処理ということは、非同期処理であるということです。非同期処理はプログラミングコードが上から下に流れない、コールバック方式になったりするので、意図した動作にならないケースがあるなど、苦労することがあります。

そこでNCMBのSwift SDKでは同期処理のように扱えるメソッドも用意しています。この記事では同期、非同期処理の使い分けを紹介します。

データを一括で検索する場合

例えばデータストア(クラウドデータベース)からデータを取り出す場合です。非同期処理の場合は次のように書きます。

query.findInBackground(callback: { result in
    switch result {
        case let .success(array): // 検索成功
            // メモデータを適用
            self.memos = array
        case let .failure(error): // 検索失敗
            print("取得に失敗しました: \(error)")
    }
})

これを同期処理で書く場合です。ぱっと見では同期処理の方が分かりやすいです。

let result = query.find()
if case let .success(array) = result {
    self.memos = array;
}

実際の描画される様子です。まず非同期の場合。

1.mov.gif

次に同期の場合。

3.mov.gif

おそらく、どちらも見た目上は変わりません。

ループ処理の伴う同期、非同期処理

次にデータを取得した後、ファイルストア(クラウドファイルストレージ)から写真データをダウンロードしてグリッドに描画する処理です。この場合、検索結果が6件あれば、6回写真のダウンロードが実行されます。

非同期の場合です。これが6回繰り返されるようなものです。

// ファイルストア用のオブジェクトを用意
let file : NCMBFile = NCMBFile(fileName: fileName)
// ダウンロード実行
file.fetchInBackground(callback: { result in
    switch result {
        case let .success(data):  // ダウンロード成功
            self.imageData = data
        case let .failure(error): // ダウンロード失敗
            print(error)
    }
})

次に同期の場合です。

// ファイルストア用のオブジェクトを用意
let file : NCMBFile = NCMBFile(fileName: fileName)
// ダウンロード実行
let result = file.fetch()
if case let .success(data) = result {
    self.imageData = data
}

同期で処理した場合です。表示までにかなり時間がかかり、一気に表示されます。これはUXがよくありません。

2.mov.gif

同期処理の仕組み

同期処理は DispatchSemaphore を使って処理をwaitし、レスポンスが返ってきたら処理を再開しています。基本的に非同期処理の 〜InBackground をラッピングしているだけです。

public func find() -> NCMBResult<[T]> {
    var result : NCMBResult<[T]> = NCMBResult.failure(NCMBApiErrorCode.genericError)
    let semaphore = DispatchSemaphore(value: 0)
    findInBackground(callback: {(res: NCMBResult<[T]>) -> Void in
        result = res
        semaphore.signal()
    })
    _ = semaphore.wait(timeout: DispatchTime.distantFuture)
    return result
}

このため、ループで同期処理を行うと、1つ目の写真から6つ目の写真まで順番に1つずつ取得する形になります。これだと時間がかかってしまいます。非同期処理の場合はパラレルでダウンロード処理されるので、写真の表示順番は保証されませんが、表示までは高速になります。

まとめ

同期処理を使うことでコードの見通しは良くなります。JavaScriptのasync/awaitのように使えるので、ぜひ活用してください。ただ、ループ処理中での利用は控えた方が、アプリのUXとして良いものになるはずです。

ドキュメント : 開発者向けドキュメント | ニフクラ mobile backend

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?