Swiftでファイルをサーバーに保存しよう！

__【お知らせ】Swift3に対応しました！（2017/02/24更新）__

# 【Swift×mBaaS】シリーズ概要
* Swiftで[ニフクラ mobile backend ](http://mb.cloud.nifty.com/)(通称：mBaaS)を使ってSwiftで開発を始めたい人向けのドキュメントです
* [ニフクラ mobile backend のiOS(Objectiv-C SDK)用ドキュメント](http://mb.cloud.nifty.com/doc/current/index.html)を__Swift__用に書き換えて動かしてみたものをまとめました
* 初心者でもわかりやすいよう心掛けて作っていますが、わかりにくい部分がありましたらコメントをいただければ訂正しますのでお気軽にご意見をお願いします^^*
* 今回は__＜ファイルストア編＞__です！

# 事前準備のお願い
* 事前に[ニフクラ mobile backend の登録](http://mb.cloud.nifty.com/)とアプリの新規作成をし、 [＜CocoaPods＞SwiftでmBaaSを始めよう！(use_framewoks!を有効にした方法)](http://qiita.com/natsumo/items/57d3a4d9be16b0490965)をご覧いただき、必要な初期設定(SDKのインストールなど)をXcode上で行った上でご利用ください
* 一部Xcodeのバージョンが古い場合は上記方法ではSDKのインストールが行えない場合があります
* その場合は、[＜CocoaPods＞SwiftでmBaaSを始めよう！](http://qiita.com/natsumo/items/b2d18d87d57300c8d81c)または[＜framework形式＞SwiftでmBaaSを始めよう！](http://qiita.com/natsumo/items/26b64121121ea2029f8d)をお試しください

# __Swiftでファイルをサーバーに保存しよう！__
* [ニフクラ mobile backend ](http://mb.cloud.nifty.com/)のダッシュボードで確認をしながらXcodeで動作確認をしてください

## ダッシュボードでの事前設定
* [ニフクラ mobile backend ](http://mb.cloud.nifty.com/)のダッシュボードを開きます
* 「アプリ設定」＞「データ・ファイルストア」＞「データストア」の「アプリからのクラス作成」を「有効」にして、「保存する」をクリックします

![スクリーンショット 2016-06-07 13.07.32.png](https://qiita-image-store.s3.amazonaws.com/0/112032/4c74c6a6-8733-723c-e1d4-a7775009e78a.png)

## ドキュメント

### __ファイルストアへのアップロード__

#### __画像データを扱う場合__
* 画像（.png）を１つ用意して、 `AppDelegate.swift`と同じディレクトリにドラッグ＆ドロップして取り込みます
 * この画像をファイルストアへアップロードしてみます★
* 下図のように画像ファイルを「`test.png`」とした場合にアップロードするドキュメントは以下のように書けます

![スクリーンショット 2016-06-07 13.01.50.png](https://qiita-image-store.s3.amazonaws.com/0/112032/372c2682-807d-9214-755b-34c5b338c3f3.png)

* `AppDelegate.swift`に記述します
* まず、`didFinishLaunchingWithOptions`メソッド内に下記内容を記述します
 * 書き込む場所がよくわからない場合は、[Swiftでデータベースを使おう！①（保存・取得・更新・削除）]()の初期設定を参照してください

```swift:Swift3_AppDelegate.swift
// ファイル名を指定して画像を生成
let fileName = "test.png"
let imageFile = UIImage(named: fileName)
if imageFile == nil {
    // ファイル名が無効だった場合
}

//////////////////////////////////////////////////////////////////////////
// 画像をリサイズする(任意)
/* Basic会員は５MB、Expert会員は100GBまでのデータを保存可能です */
/* 上限を超えてしまうデータの場合はリサイズが必要です */
let imageW : Int = Int(imageFile!.size.width*0.2) /* 20%に縮小 */
let imageH : Int = Int(imageFile!.size.height*0.2) /* 20%に縮小 */
let resizeImage = resize(image: imageFile!, width: imageW, height: imageH)
//////////////////////////////////////////////////////////////////////////

// 画像をNSDataに変換
let pngData = NSData(data: UIImagePNGRepresentation(resizeImage)!)
let file = NCMBFile.file(withName: fileName, data: pngData as Data!) as! NCMBFile

// ファイルストアへ画像のアップロード
file.saveInBackground({ (error) in
    if error != nil {
        // 保存失敗時の処理
    } else {
        // 保存成功時の処理
    }
}) { (int) in
    // 進行状況を取得するためのBlock
    /* 1-100のpercentDoneを返す */
    /* このコールバックは保存中何度も呼ばれる */
    /*例）*/
    print("\(int)%")
}
```

```swift:Swift2_AppDelegate.swift
// ファイル名を指定して画像を生成
let fileName = "test.png"
let imageFile = UIImage(named: fileName)
if imageFile == nil {
    // ファイル名が無効だった場合
}

//////////////////////////////////////////////////////////////////////////
// 画像をリサイズする(任意)
/* Basic会員は５MB、Expert会員は100GBまでのデータを保存可能です */
/* 上限を超えてしまうデータの場合はリサイズが必要です */
let imageW : Int = Int(imageFile!.size.width*0.2) /* 20%に縮小 */
let imageH : Int = Int(imageFile!.size.height*0.2) /* 20%に縮小 */
let resizeImage = resize(imageFile!, width: imageW, height: imageH)
//////////////////////////////////////////////////////////////////////////

// 画像をNSDataに変換
let pngData = NSData(data: UIImagePNGRepresentation(resizeImage)!)
let file = NCMBFile.fileWithName(fileName, data: pngData) as! NCMBFile

// ファイルストアへ画像のアップロード
file.saveInBackgroundWithBlock({ (error: NSError!) -> Void in
    if error != nil {
        // 保存失敗時の処理
    } else {
        // 保存成功時の処理   
    }
}, progressBlock: { (int: Int32) -> Void in
    // 進行状況を取得するためのBlock
    /* 1-100のpercentDoneを返す */
    /* このコールバックは保存中何度も呼ばれる */
})
```

* 次に、今追記していた`didFinishLaunchingWithOptions`メソッドの下（外側）に、下記のコードを
記述します


```swift:Swift3_AppDelegate.swift
// 画像をリサイズする処理
func resize (image: UIImage, width: Int, height: Int) -> UIImage {
    let size: CGSize = CGSize(width: width, height: height)
    UIGraphicsBeginImageContext(size)
    image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    let resizeImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    
    return resizeImage!
}
```


```swift:Swift2_AppDelegate.swift
// 画像をリサイズする処理
func resize (image: UIImage, width: Int, height: Int) -> UIImage {
    let size: CGSize = CGSize(width: width, height: height)
    UIGraphicsBeginImageContext(size)
    let resizeImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return resizeImage
}
```


#### __画像以外のデータの場合__

* 「Test Message」と書かれた 「test.txt」ファイルをアップロードする場合

```swift:Swift3_AppDelegate.swift
// データを作成
let data = "Test Message".data(using: String.Encoding.utf8)
// ファイル名とデータを指定してNCMBオブジェクトを生成
let file = NCMBFile.file(withName: "test.txt", data: data) as! NCMBFile
// ファイルストアにアップロード
file.save(nil)
```

```swift:Swift2_AppDelegate.swift
// データを作成
let data = "Test Message".dataUsingEncoding(NSUTF8StringEncoding)
// ファイル名とデータを指定してNCMBオブジェクトを生成
let file = NCMBFile.fileWithName("test.txt", data: data)
// ファイルストアにアップロード
file.save(nil)
```

### __ファイルの取得__

* `Main.storyboard`に取得したファイル（`.png`）を表示する`imageView`を作成しておきます
* 作成した`imageView`は、`myImgaeView`として`ViewController.swift`に紐付けておきます

![スクリーンショット 2016-06-07 14.55.58.png](https://qiita-image-store.s3.amazonaws.com/0/112032/f9fc8dad-e9c3-0049-7587-44e31897b1bf.png)

* `ViewController.swift`の`viewDidLoad`メソッドにファイル取得処理を書きます
* 次のコードは取得した画像ファイルを`myImageView`に表示するドキュメントです

```swift:Swift3_ViewController.swift
import UIKit
import NCMB

class ViewController: UIViewController {
    // ImageView作成
    @IBOutlet weak var myImageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 画面表示時に実行される
        let fileData = NCMBFile.file(withName: "test.png", data: nil) as! NCMBFile
        fileData.getDataInBackground { (data, error) in
            if error != nil {
                // ファイル取得失敗時の処理
            } else {
                // ファイル取得成功時の処理
                let image = UIImage.init(data: data!)
                self.myImageView.image = image
                self.view.addSubview(self.myImageView)
            }
        }  
    }
}
```

```swift:Swift2_ViewController.swift
import UIKit
import NCMB

class ViewController: UIViewController {
    // ImageView作成
    @IBOutlet weak var myImageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 画面表示時に実行される
        let fileData = NCMBFile.fileWithName("test.png", data: nil)
        fileData.getDataInBackgroundWithBlock { (data: NSData!, error: NSError!) -> Void in
            if error != nil {
                // ファイル取得失敗時の処理
            } else {
                // ファイル取得成功時の処理
                let image = UIImage.init(data: data)
                self.myImageView.image = image
                self.view.addSubview(self.myImageView)
                
            }
        }  
    }
}
```

* ファイルの検索を利用することもできます
* クエリを取得して、ファイルストアを検索して取得した場合のドキュメントです

```swift:Swift3_ViewController.swift
// ファイルストアを検索するクエリを作成
let query = NCMBFile.query()
// 検索するファイル名を設定
query?.whereKey("fileName", equalTo: "test.png")
// ファイルストアの検索を実行
query?.findObjectsInBackground({ (files, error) in
    if error != nil {
        // 検索失敗時の処理
    } else {
        // 検索成功時の処理
        for file in files! as! [NCMBFile] {
            file.getDataInBackground({ (data, error) in
                if error != nil {
                    // ファイル取得失敗時の処理  
                } else {
                    // ファイル取得成功時の処理
                    let image = UIImage.init(data: data!)
                    self.myImageView.image = image
                    self.view.addSubview(self.myImageView)
                }
            })
        }
    }
})
```

```swift:Swift2_ViewController.swift
// ファイルストアを検索するクエリを作成
let query = NCMBFile.query()
// 検索するファイル名を設定
query.whereKey("fileName", equalTo: "test.png")
// ファイルストアの検索を実行
query.findObjectsInBackgroundWithBlock { (files: [AnyObject]!, error: NSError!) -> Void in
    if error != nil {
        // 検索失敗時の処理
    } else {
        // 検索成功時の処理
        for file in files {
            file.getDataInBackgroundWithBlock({ (data: NSData!, error: NSError!) -> Void in
                if error != nil {
                    // ファイル取得失敗時の処理
                } else {
                    // ファイル取得成功時の処理
                    let image = UIImage.init(data: data)
                    self.myImageView.image = image
                    self.view.addSubview(self.myImageView)        
                }
            })
        }
    }
}
```

### __ファイルの削除__

* deleteメソッドを利用して、ファイルを削除することができます

```swift:Swift3
file.deleteInBackground(nil)
```

```swift:Swift2
file.deleteInBackgroundWithBlock(nil)
```

# 参考
* その他、ダッシュボードでのファイルのアップロードに関しては`Objective-C`と同様の操作で行えます
* 詳しくは[【iOS】ドキュメント＞ファイルストア](http://mb.cloud.nifty.com/doc/current/filestore/basic_usage_ios.html)をご覧ください