4. チュートリアル1 : TODOアプリ (Swift版)

本チュートリアルは、チュートリアル1(Objective-C)版と全く同じですが、 実装を Objective-C ではなく Swift で行っています。

BaaSサーバ側の設定手順は Objective-C 版と同じため割愛します。

4.1. サンプルコードの変更と実行

チュートリアル1(Swift)のサンプルコードを設定し、動作させてみます。

Xcode から tutorial1-swift ディレクトリを開いてください。

NebulaTutorial1/Config.swift ファイルを修正します。

// テナントID
let TENANT_ID = ""

// アプリケーションID
let APP_ID = ""

// アプリケーションキー
let APP_KEY  = ""

// エンドポイント URI
let ENDPOINT_URI = "https://baas.example.com/api/";

テナントID, アプリケーションID/キー, エンドポイントURIを指定します。 内容は Objective-C 版と同じです。 変更が完了したら、ビルド・実行してください。

以下、実装手順について説明します。

4.2. NEC BaaS SDK Framework の追加

NEC BaaS iOS SDK を利用するためには、アプリケーションに Nebula SDK Framework を追加する必要があります。この手順は Objective-C 版と同じです。

4.3. ヘッダファイルの import

iOS SDK を使用するソースファイルは、適宜 Nebula.h ファイルを import する必要があります。 Swift を使用するプロジェクトでは、Bridging ヘッダ(プロジェクト名-Bridging-Header.h)に以下の1行を追加します。

#import <NecBaas/Nebula.h>

4.4. AppDelegate クラス

AppDelegate クラスの application() メソッド内で、 iOS SDK の初期化処理を行います。

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject:AnyObject]?) -> Bool {
    // Nebula 初期化処理
    NBCore.setUpWithAppId(APP_ID, appKey: APP_KEY, tenantId: TENANT_ID);
    NBCore.setEndPointUri(ENDPOINT_URI);
    return true;
}

SDK の初期化には NBCore クラスを使用します。 setupWithAppId() を使用して以下のパラメータを設定します。

  • テナントID
  • アプリケーションID
  • アプリケーションキー

また、setEndPointUri() を使用して、エンドポイントURIを設定します。

4.5. TodoListViewController クラス

アプリケーション本体は TodoListViewController クラスに実装します。 本クラスは UITableViewController を継承しており、Todo を Table View で表示します。

4.5.1. 初期化 (viewDidLoad)

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "TodoCell")

    reloadTodos(nil)
}

初期化は viewDidLoad で行います。

ここでは reloadTodos() を呼び出し、Todo 一覧の取得を開始しています。

4.5.2. Todo 一覧の取得

// Todo 一覧を取得する
@IBAction func reloadTodos(sender: UIButton?) {
    // バケット取得
    var bucket = NBObjectBucket(bucketName: BUCKET_NAME)

    // クエリ生成
    var query = NBQuery()
    query.setSortOrderWithKey("updatedAt", isAscend: true)

    // クエリ実行
    bucket.queryInBackgroundWithQuery(query, block: {objects, count, error in
        self.hideIndicator()
        if (error == nil) {
            self.todos = objects as [NBObject];
            self.tableView.reloadData()
        } else {
            NSLog("query error: %@", error)
        }
    })
    showIndicator()
}

reloadTodos() で、サーバから Todo データの一覧を取得します。

最初にオブジェクトバケットのインスタンスを取得します。オブジェクトバケットは NBObjectBucket クラスの インスタンスとして作成し、コンストラクタでバケット名をセットします。

Todo データは、NBObjectBucket に対して queryInBackgroundWithQuery() を呼び出すことで取得できます。 クエリ(取得条件)は NBQuery クラスのインスタンスとして作成します。 ここでは更新日時(updatedAt)フィールド昇順で、全件取得するというクエリを作成しています。

処理が完了すると、block: 引数に指定したクロージャが呼び出されます。 正常時は objects にオブジェクトの一覧が、error に nil が格納されます。 ここでは todos プロパティに objects を保存し、tableView の reloadData を呼び出して画面描画を行います。

4.5.3. 画面描画

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return todos.count;
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    tableView.dequeueReusableCellWithIdentifier("TodoCell");
    var cell = tableView.dequeueReusableCellWithIdentifier("TodoCell") as UITableViewCell

    var todo = todos[indexPath.row]
    cell.textLabel?.text = todo.objectForKey("description") as? String

    return cell
}

UITableView の描画は UITableViewDelegate の対応するメソッドで行います。

サーバから取得した Todo データは todos プロパティに格納されています。 numberOfRowsInSection() は、todos に格納されているオブジェクト数をテーブルの行数として返します。

cellForRowAtIndexPath() で、具体的な TableView の cell を返却します。 todos の indexPath.row 番目の要素を取り出し、"description" キーに格納された文字列を cell のテキストとして 設定して返却します。

4.5.4. Todo の追加

画面右上の Add ボタンを押すと、Todo の追加処理に移ります。 この処理は Segue 経由で TodoEditViewController を起動することで行っています。

TodoEditViewController の Done ボタンを押すと TodoListViewController に戻りますが、 この際 todoText プロパティに設定されたテキストを保管します。

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    self.todoText = self.textView!.text;
}

TodoListViewController は、上記テキストを取り出し、addTodo() を呼び出します。

@IBAction func firstViewReturnActionForSegue(segue: UIStoryboardSegue) {
    if (segue.identifier == "done") {
        var vc = segue.sourceViewController as TodoEditViewController
        var todo = vc.todoText
        addTodo(todo)
    }
}

addTodo() では、Todo の追加処理を行います。

func addTodo(description: String) {
    // オブジェクト作成
    var todo = NBObject(bucketName: BUCKET_NAME)

    // オブジェクトに値を設定
    todo.setObject(description, forKey: "description")

    // オブジェクト保存
    showIndicator()

    todo.saveInBackgroundWithBlock({objects, count, error in
        self.hideIndicator()
        if (error == nil) {
            self.reloadTodos(nil)
        } else {
            NSLog("save error : %@", error);
        }
    })
}

Todo データを NBObject クラスのインスタンスとして生成します。このとき、バケット名を指定します。

また、setObject() を呼び出して、description フィールドに Todo のテキストをセットします。

データの保存には saveInBackgroundWithBlock() メソッドを使用します。 このメソッドが呼び出されるとサーバにデータが送信され、処理が終了するとクロージャが呼び出されます。 ここでは reloadTodos() を呼び出して画面更新処理を行います。

4.5.5. Todo の削除

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return true // 削除可能
}

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    var obj = todos[indexPath.row]


    // オブジェクト削除
    obj.deleteInBackgroundWithBlock({error in
        self.hideIndicator()
        if (error == nil) {
            self.reloadTodos(nil)
        } else {
            NSLog("Delete failed: %@", error)
        }
    })
    showIndicator()
}

Todo の削除処理は、tableView:commitEditingStyle:forRowAtIndexPath: で行います。 本処理は、Todo を左スワイプしたときに呼び出されます。

todos プロパティから、該当 NBObject インスタンスを取得し、 deleteInBackgroundWithBlock() を呼び出すとサーバに削除指示が送信されます。

削除が正常に完了するとクロージャが呼び出されますので、画面をリロードします。