開発メモ

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

Nifty Cloud Mobile Backendのデータストア・基本編

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

今回は、データストアの基本的な使い方を調べてみました。具体的には、オブジェクトのサブクラス化・保存・読み込み・更新・削除などです。

とりあえず、ソースコードを公開してあるので、よくわからない部分は直接見てもらった方が早いでしょう。たぶん。

See_Ku / NcmbDatastoreDemo — Bitbucket
https://bitbucket.org/See_Ku/ncmbdatastoredemo

実際に動かすと、こんな画面になります。

f:id:see_ku:20160219202950p:plain

動作を確認した環境

環境 情報
Xcode 7.2.1 (7C1002)
iOS 9.2
Swift 2.1.1
Date 2016/2/18
NCMB SDK 2.2.5

オブジェクトのサブクラス化

簡単に言うと、NCMBObjectを継承したクラスを作ることで、普通のSwiftのクラスっぽくデータを使えるようにする方法です。

今回のデモではこんな感じにしてあります。

import NCMB

@objc(StoreData)
class StoreData: NCMBObject, NCMBSubclassing {

    // /////////////////////////////////////////////////////////////
    // MARK: - NCMBSubclassing

    /// mobile backend上のクラス名を返却する
    static func ncmbClassName() -> String! {
        return "StoreData"
    }

    // /////////////////////////////////////////////////////////////
    // MARK: - property

    /// 文字列型のプロパティ
    var name: String! {
        get {
            if let str = objectForKey("name") as? String {
                return str
            } else {
                return ""
            }
        }

        set {
            setObject(newValue, forKey: "name")
        }
    }

    /// 数値型のプロパティ
    var number: Int {
        get {
            if let num = objectForKey("number") as? NSNumber {
                return num.integerValue
            } else {
                return 0
            }
        }

        set {
            setObject(NSNumber(integer: newValue), forKey: "number")
        }
    }
}

ポイントをまとめるとしたらこんな感じでしょうか?

  • @objcで内部のクラス名をObjective-Cの形式にあわせる必要がある
  • NCMBObjectの継承とNCMBSubclassingの適応が必要
  • ncmbClassName()でクラス名を返す必要がある
  • Swiftのプロパティのget/setで値への操作を隠蔽

この他に、AppDelegateでクラスを登録する処理も必要になります。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    // サブクラス化したNCMB向けクラスを登録
    StoreData.registerSubclass()

    以下略

全体的に、あまりSwiftっぽく無いのが残念ポイントですね。いろいろと努力すればもう少しマシになりますが、今回はデータストアのデモということで止めておきました。

データストアへオブジェクトを保存

オブジェクトを保存する部分はこんな感じになります。

/// 新しいデータを作成
func createData() {

    // 新しいデータを作成
    let data = StoreData.object() as! StoreData
    data.name = "---"
    data.number = 0

    // 非同期で保存
    data.saveInBackgroundWithBlock() { error in
        if let error = error {
            print("create error: \(error)")
            return
        }

        print("create ok: ")

        // 画面を更新
        let main = dispatch_get_main_queue()
        dispatch_async(main) {
            self.readDataSync()
            self.tableView.reloadData()
        }
    }
}

新しくデータを入れたオブジェクトを作って、非同期で保存してるだけです。簡単ですね。

データを作成する部分がSwiftっぽく無いですが(以下略)

データストアからオブジェクトを読み込み(検索)

データを読み込む部分はこんな感じになりました。

var dataArray: [StoreData]?

/// データを読み込み ※同期処理
func readDataSync() {
    let query = StoreData.query()
    query.limit = 20

    do {
        dataArray = try query.findObjects() as? [StoreData]
        print("read ok: \(dataArray?.count)")

    } catch {
        print("read error: \(error)")
        dataArray = nil
    }
}

Nifty Cloud Mobile Backendのサイトのサンプルを参考にしたため、ここは同期処理になってます。本来なら、非同期にするべきでしょう。

データストアのオブジェクトを更新

データの更新は保存と同じ処理ですね。

/// データを更新
func updateData() {
    guard let data = editData else { return }

    // 非同期で保存(更新)
    data.saveInBackgroundWithBlock() { error in
        if let error = error {
            print("update error: \(error)")
        } else {
            print("update ok: ")
        }
    }
}

先頭で編集したデータを取り出して、後は保存してるだけです。objectIdが設定済みのオブジェクトを保存すれば、自動的に更新になる、と。

データストアのオブジェクトを削除

データの削除は更新とよく似てます。

/// データを削除
func deleteData() {
    guard let data = editData else { return }

    // 非同期で削除
    data.deleteInBackgroundWithBlock() { error in
        if let error = error {
            print("delete error: \(error)")
        } else {
            print("delete ok: ")
            self.editData = nil
            self.configureView()
        }
    }
}

objectIdが設定済みのオブジェクトに対して、削除を実行してるだけです。簡単ですね。

感想

いわゆるCRUDっぽい事をやるだけであれば、特に悩むこともなく実現可能でした。

どちらかというと、端々に表れるSwiftっぽく無い処理をどうするかの方が課題になるのかもしれません。