【Swift】 Nifty Cloud mobile backendを使って、CRUD(データの送信、受信、更新、削除)をやってみた

# はじめに
本記事では、Nifty Cloud mobile backendをiOSで使う際に必要になるデータの操作について簡単に紹介します。

# 開発環境
Xcode 7.3.1
Nifty Cloud mobile backend 2.3.2

# Nifty Cloud mobile backendのインストール
こちらに記載されていますので、詳しくは下記のリンクを御覧ください。
[Nifty Cloud mobile backend クイックスタート](http://mb.cloud.nifty.com/doc/current/introduction/quickstart_ios.html)
## Cocoapods

```pod init```で生成されたPodfileに以下の一文を追加します。

```:Podfile
pod 'NCMB', :git => 'https://github.com/NIFTYCloud-mbaas/ncmb_ios.git'
```

あとは、```pod install```または```pod update```をすれば、インストールは完了です

## Carthage
touchでCartfileを作成し、そのCarfileに以下の一文を追加します。

```:Cartfile
github "NIFTYCloud-mbaas/ncmb_ios"
```

あとは、```carthage update --platform iOS```をすれば完了です。

# モデルクラス

まず、モデルクラスをつくります。
モデルクラスのテンプレートが下記のコードになります。

```swift:Model.swift
import Foundation
import NCMB // Nifty Cloud mobile backendをインポート

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

    var column: Int {
        get {
            return objectForKey("column") as! Int
        }
        set {
            setObject(newValue, forKey: "column")
        }
    }
    //　必須 呼び出すときに、Class Nameを指定
    override init!(className: String!) {
        super.init(className: className)
    }

    // 必須。
    static func ncmbClassName() -> String! {
        return "Model"
    }
}
```

今回は、本のデータベースを作成するアプリをサンプルとしてつくりましたので、BooksとAuthersという本と著者をそれぞれRDBのテーブルにしました。
BooksのテーブルとAuthersのテーブルもリレーションシップを持っていますので、その方法も参考にしていただければとおもいます。

上記のモデルクラスにを使うと下記のモデルクラスを作成することになります。

```swift:Books.swift
import Foundation
import NCMB // Nifty Cloud mobile backendをインポート

@objc(Books)
class Books: NCMBObject, NCMBSubclassing {
    
    // それぞれのカラムを指定
    var title: String! {
        get {
            return objectForKey("title") as! String
        }
        set {
            setObject(newValue, forKey: "title")
        }
    }
    
    var publishedDate: NSDate {
        get {
            return objectForKey("publishedDate") as! NSDate
        }
        set {
            setObject(newValue, forKey: "publishedDate")
        }
    }
    
    var isPublic: Int {
        get {
            return objectForKey("isPublic") as! Int
        }
        set {
            setObject(newValue, forKey: "isPublic")
        }
    }
    
    var user: NCMBUser {
        get {
            return objectForKey("user") as! NCMBUser
        }
        set {
            setObject(newValue, forKey: "user")
        }
    }
    
    var auther: Authers {
        get {
            return objectForKey("auther") as! Authers
        }
        set {
            setObject(newValue, forKey: "auther")
        }
    }
    
    //　必須 呼び出すときに、Class Nameを指定
    override init!(className: String!) {
        super.init(className: className)
    }
    
    // 必須。
    static func ncmbClassName() -> String! {
        return "Books"
    }
}
```

```swift:Authers.swift
import Foundation
import NCMB // Nifty Cloud mobile backendをインポート

@objc(Authers)
class Authers: NCMBObject, NCMBSubclassing {
    
    // それぞれのカラムを指定
    var familyName : String {
        get {
            return objectForKey("familyName") as! String
        }
        set {
            setObject(newValue, forKey: "familyName")
        }
    }
    
    var firstName: String {
        get {
            return objectForKey("firstName") as! String
        }set {
            setObject(newValue, forKey: "firstName")
        }
    }
    
    //　必須 呼び出すときに、Class Nameを指定
    override init!(className: String!) {
        super.init(className: "Authers")
    }
    
    // 必須。
    static func ncmbClassName() -> String! {
        return "Authers"
    }
}
```

# Create(データの作成、送信)
データの保存の方法としては、saveInBackgroundやsaveInBackgroundWithBlockなどいろいろありますが、本記事ではsaveEventuallyを使います。

モデルクラスで、まず保存するためのデータを作成するためのメソッドを用意しました。

```swift:Books.swift
    // 保存・作成するためのNCMBObject(Books)を作成するためのメソッド
    static func create(title: String, date: NSDate, isPublic: Int, user: NCMBUser, auther: Authers) -> Books{
        // インスタンスを作成
        let book = Books(className: "Books")
        // それぞれのプロパティに適切なデータを入れる
        book.auther = auther
        book.isPublic = isPublic
        book.title = title
        book.user = user
        book.publishedDate = date
        return book
    }
```

```swift:Authers.swift
    // 保存・作成するためのNCMBObject(Books)を作成するためのメソッド
    static func create(firstName: String, familyName: String) -> Authers {
        // インスタンスを作成
        let auther = Authers(className: "Authers")
        // それぞれのプロパティに適切なデータを入れる
        auther.familyName = familyName
        auther.firstName = firstName
        return auther
    }
```

次に作成したデータを実際に保存するためのコードをモデルクラスに記載します。

```swift:Books.swift
    // データを非同期で通信状況に合わせて送信する
    func saveWithEvent(callback: () -> Void) {
        self.saveEventually { (error) in
            if error != nil { // エラーがあるとき
                print(error.localizedDescription)
            }else { // エラーがないとき
                // 引数で受け取った処理を行う
                callback()
            }
        }
    }
```

```swift:Authers.swift
    // データを非同期で通信状況に合わせて送信する
    func saveWithEvent(callback: () -> Void) {
        self.saveEventually { (error) in
            if error != nil { // エラーがあるとき
                print(error.localizedDescription)
            }else { // エラーがないとき
                // 引数で受け取った処理を行う
                callback()
            }
        }
    }
```

あとは、それぞれのViewControllerで、以下のように保存の処理を記述すれば大丈夫です。

```swift:ViewController.swift
    func create(title: String, date: NSDate, whichPublic: Int, autherObject: Authers) {
        //モデルクラスからcreateを呼び出し、その後、saveWithEventで保存処理を行う
        Books.create(title, date: date, isPublic: whichPublic, user: NCMBUser.currentUser(), auther: autherObject).saveWithEvent {
            self.navigationController?.popViewControllerAnimated(true)
        }
    }
```

# Read(データの取得)
次に、Nifty Cloudのクエリを使ってデータを取得します。モデルクラスの中でloadAllというメソッドとして、以下のように記述します

```swift:Books.swift
    // Booksテーブルからすべてを取得
    static func loadAll(callback: (objects: [Books]) -> Void) {
        // NCMBQueryをクエリとして作成
        let query = NCMBQuery(className: "Books")
        query.includeKey = "auther"
        // クエリに従ってすべてを取得
        query.findObjectsInBackgroundWithBlock { (objects, error) in
            if error != nil { // エラーがあるとき
                print(error.localizedDescription)
            }else { // エラーがないとき
                // 取得したデータをBooksクラスに変換
                let obj = objects as! [Books]
                print("autherとは...\(obj[0].auther)")
                print(obj)
                // 引数で受け取った処理を行う
                callback(objects: obj)
            }
        }
    }
```

```Authers.swift
    // Booksテーブルからすべてを取得
    static func loadAll(callback: (objects: [Authers]) -> Void) {
        // NCMBQueryをクエリとして作成
        let query = NCMBQuery(className: "Authers")
        // クエリに従ってすべてを取得
        query.findObjectsInBackgroundWithBlock { (objects, error) in
            if error != nil { // エラーがあるとき
                print(error.localizedDescription)
            }else { // エラーがないとき
                // 取得したデータをBooksクラスに変換
                let obj = objects as! [Authers]
                print(obj)
                // 引数で受け取った処理を行う
                callback(objects: obj)
            }
        }
    }
```

それぞれのViewControllerでの呼び出し方は以下の記述のとおりです。
今回はTableViewにデータを表示しています。

```swift:ViewController.swift
    func read() {
        Books.loadAll { (objects) in
            //booksという配列に取得したデータを入れる
            self.books = objects
            //TableViewをリフレッシュ
            self.table.reloadData()
        }
    }
```
# Update(データの更新)

データの更新はCreateの時とほぼおなじです。異なるのは、Createの時と違い、インスタンスをつくらなくてよい点です。

モデルクラスのupdateのメソッドを以下のように記述します。

```swift:Books.swift
    // データを更新するためのメソッド
    static func update(object: Books, user: NCMBUser, title: String, date: NSDate, isPublic: Int, auther: Authers) -> Books{
        //作成したユーザーのみに編集権限を与えるために、if文を追加
        if object.user == user {
            object.title = title
            object.auther = auther
            object.isPublic = isPublic
            object.publishedDate = date
        }
        return object
    }
```

```swift:Authers.swift
    // データを更新するためのメソッド
    static func update(object: Authers, firstName: String, familyName: String) -> Authers {
        object.familyName = familyName
        object.firstName = firstName
        return object
    }
```

更新したデータを保存するためのメソッドはCreateと同じものを使います。

# Delete(データの削除)
データの削除では、取得済みのデータもしくは、IDがを使う必要があります。
deleteEventuallyをそのデータに対して、行うだけで削除が行えます。

IDを使って削除するやり方は要望があれば、追記いたします。

```swift:ViewController
    func deleteObject(indexPath: NSIndexPath) {
        let object = books[indexPath.row]
        object.deleteEventually { (error) in
            if error != nil {
                print(error.localizedDescription)
            }
        }
    }
```

#サンプルコード
コメントアウトも順次増やしていく予定ですので、参考にしていただければとおもいます
https://github.com/ShinokiRyosei/NiftyCloud-Sampler