開発メモ

開発関係のメモをいろいろと。たぶん。

Nifty Cloud Mobile Backendのファイルストア・基本編

Nifty Cloud Mobile Backendでいろいろやってみようシリーズ、第5弾(?)

今回はファイルストアを利用して、画像データのアップロード/ダウンロードの処理を試してみました。

f:id:see_ku:20160309201403p:plain

ソースコードを公開してあるので、よくわからない部分は直接見て下さい。

See_Ku / NcmbFilestoreDemo — Bitbucket
https://bitbucket.org/See_Ku/ncmbfilestoredemo

動作を確認した環境

環境 情報
Xcode 7.2.1 (7C1002)
iOS 9.2
Swift 2.1.1
Date 2016/3/9
NCMB SDK 2.3.0

画像データの保存(アップロード)

UIImageJPEGRepresentation()でNSDataにして、あとはNCMBFile::saveInBackgroundWithBlock()で保存しているだけです。

画像データのアップロードする場合、Nifty Cloud Mobile Backend側のファイルサイズ制限に引っ掛からないようにする点が問題になりそうですが、ここでは『UIImagePickerControllerの編集結果なら大丈夫』という楽観論で通してあります。

本番用のアプリでは、このような手抜きはやめましょう。

@IBAction func onUpload(sender: AnyObject) {

    // 画像ファイルをJPEG形式でデータ化
    guard let image = imageView.image else { return }
    guard let data = UIImageJPEGRepresentation(image, 0.95) else { return }

    // ※本来ならここでサイズのチェックが必要

    // NCMBFileを生成
    let fn = NSUUID().UUIDString + ".jpg"
    let file = NCMBFile.fileWithName(fn, data: data)

    // アップロード
    file.saveInBackgroundWithBlock() { error in
        if let error = error {
            print("File save error : ", error)
        } else {
            print("File save OK: \(fn)")
        }
    }
}

画像データの取得(ダウンロード)

ファイルの情報を取得

ファイルの情報を取得する所まではデータストアとほぼ同じです。使用するクラスがNCMBFile()になったぐらいでしょうか?

この後、実際のデータを取得する処理が入ります。

/// データを読み込み ※情報取得までは同期処理
func readDataSync() {
    let query = NCMBFile.query()
    query.limit = 20

    do {
        fileArray = try query.findObjects() as? [NCMBFile]
        fetchData()

        print("read ok: \(fileArray?.count)")
    } catch {
        fileArray = nil

        print("read error: \(error)")
    }
}

実際のデータを取得

NCMBFileのgetDataInBackgroundWithBlock()でデータを取得しているだけです。簡単そうに見えますよね?

/// データの取得処理を実行
func fetchData() {
    guard let ar = fileArray else { return }

    for file in ar {

        // 取得済みのデータはスキップ
        if imageDic[file.name] != nil {
            print("imageDic: \(file.name)")
            continue
        }

        // データを取得
        file.getDataInBackgroundWithBlock() { data, error in
            if let error = error {
                print("get error: \(error)")

            } else {
                let image = UIImage(data: data)
                self.imageDic[file.name] = image
                self.collectionView.reloadData()

                print("get file.name: \(file.name)")
            }
        }
    }
}

実は、この部分の処理にはいろいろと課題や問題点があります。

  • ファイルをローカルにキャッシュする仕組みが無い
    少なくとも、Nifty Cloud Mobile Backend iOS SDK v2.3.0には、そのような機能は無いようです。getDataInBackgroundWithBlock()を呼び出すと、その回数だけ、毎回毎回、サーバーに取りに行ってくれます。必要であれば自力でキャッシュする仕組みを作りましょう。

  • getDataInBackgroundWithBlock()は内部でシリアライズされない
    getDataInBackgroundWithBlock()を10回呼んだら10本、20回呼んだら20本、同時に処理が走ってしまいます。出来れば、ある程度呼び出しを制限する仕組みを自力で作った方が良いでしょう。

  • 同じファイルへの同時取得を考慮してくれない
    同じファイルにアクセスに行った場合、素直に、同時に取得処理が走ります。この部分も、自力でどうにかして無駄にアクセスしないような仕組みを作るべきでしょう。

・・・SDKを使っても、意外と面倒な事が多いですね。

その他

SDKのソースを読んでいて、少し気になった点です。

  • NCMBFile::isDirtyはサーバーでの変更に関知してない?
    単純に、サーバーに保存済みかどうかのフラグのようです。サーバー側でデータが更新されたかどうかのチェックには使えない模様です。

  • NCMBFile::isDataAvailableが機能してない?
    まったく、何の処理もしていないように思えるんですが・・・ 何なんでしょうね、これ。