0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Swift SDKを使って写真をNCMBへアップロードする

Last updated at Posted at 2021-06-23

ニフクラ mobile backendでは各種言語向けにSDKを提供しています。その中で最も新しいSwift SDKについて、その使い方を紹介します。

今回はファイルストア(バイナリファイルのストレージ機能)を使って、撮影した写真をアップロードします。

イントロダクション (Swift) : クイックスタート | ニフクラ mobile backend

謝辞

この記事を書くにあたって、写真を撮影またはライブラリから取得する部分のコードを【SwiftUI】カメラ機能の実装方法【撮影画像とライブラリー画像の利用】から拝借しています。ありがとうございます。

import SwiftUI

struct Imagepicker : UIViewControllerRepresentable {
    
    @Binding var show:Bool
    @Binding var image:Data
    var sourceType:UIImagePickerController.SourceType
 
    func makeCoordinator() -> Imagepicker.Coodinator {
        
        return Imagepicker.Coordinator(parent: self)
    }
      
    func makeUIViewController(context: UIViewControllerRepresentableContext<Imagepicker>) -> UIImagePickerController {
        
        let controller = UIImagePickerController()
        controller.sourceType = sourceType
        controller.delegate = context.coordinator
        
        return controller
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<Imagepicker>) {
    }
    
    class Coodinator: NSObject,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
        
        var parent : Imagepicker
        
        init(parent : Imagepicker){
            self.parent = parent
        }
        
        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            self.parent.show.toggle()
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            
            let image = info[.originalImage] as! UIImage
            let data = image.jpegData(compressionQuality: 0.8)
            self.parent.image = data!
            self.parent.show.toggle()
        }
    }
}

Swift SDKの導入法

Swift SDKはCocoaPods向けに提供しています。Xcodeで新しいiOSプロジェクトを作ったら、Podfileを用意します。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'todoapp' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for todoapp
  pod 'NCMB', :git => 'https://github.com/NIFCLOUD-mbaas/ncmb_swift.git'
end

そして pod install でSwift SDKをインストールします。

初期化について

現在、新規でiOSアプリを作成すると、InterfaceがSwiftUI、Life CycleがSwiftUI Appとなっています。この状態で作ると AppDelegate.swift はなく、 (アプリ名)App.swift というファイルが作られます。

この場合、まずSwift SDKを読み込みます。

import SwiftUI
import NCMB   // 追加

そして var body の上に @Environment を追加します。

@Environment(\.scenePhase) private var scenePhase // 追加
var body: some Scene {

最後に WindowGrouponChange を追加します。このonChangeの中で初期化処理を行います。

WindowGroup {
    ContentView()
}
.onChange(of: scenePhase) { scene in
    switch scene {
    case .active:
        NCMB.initialize(applicationKey: "YOUR_APPLICATION_KEY", clientKey: "YOUR_CLIENT_KEY")
    case .background:
        print("background")
    case .inactive:
        print("inactive")
    @unknown default:
        print("default")
    }
}

これで利用可能になります。

必要なステートを準備

まず写真データを扱うために必要なステートを準備します。

struct ContentView: View {
    // 画像データが入ります
    @State var imageData : Data = .init(capacity:0)
    // フォトライブラリまたはカメラの指定が入ります
    @State var source:UIImagePickerController.SourceType = .photoLibrary
    // イメージピッカーの表示/非表示を切り替えます
    @State var isImagePicker = false
    // アップロード状態を管理します
    @State var uploaded = false

    // : 略
}

表示内容の作成

次に表示内容を作ります。イメージピッカー部分も合わせて記載しています。

// 表示    
var body: some View {
        NavigationView{
            VStack(spacing:0){
                    ZStack{
                        // イメージピッカーの表示/非表示用
                        NavigationLink(
                            destination: Imagepicker(show: $isImagePicker, image: $imageData, sourceType: source),
                            isActive:$isImagePicker,
                            label: {
                                Text("")
                            })
                        VStack{
                            // イメージデータの有無で表示路切り替え
                            if imageData.count != 0{
                                // イメージデータがある場合
                                // 画像を表示
                                Image(uiImage: UIImage(data: self.imageData)!)
                                    .resizable()
                                    .aspectRatio(contentMode: .fill)
                                    .frame(height: 250)
                                    .cornerRadius(15)
                                    .padding()
                                // アップロード用ボタンの表示
                                Button(action: {
                                    // 後述
                                }, label: {
                                    Text("アップロード")
                                })
                                .alert(isPresented: $uploaded, content: {
                                    // アップロード完了したらアラート
                                    Alert(title: Text("アップロード完了"), message: Text("写真をアップロードしました"), dismissButton: .default(Text("閉じる")))
                                })
                            }
                            // 写真撮影またはフォトライブラリを開くボタン
                            HStack(spacing:30){
                                // フォトライブラリを開く
                                Button(action: {
                                    self.source = .photoLibrary
                                    self.isImagePicker.toggle()
                                }, label: {
                                    Text("フォトライブラリ")
                                })
                                // カメラを開く
                                Button(action: {
                                    self.source = .camera
                                    self.isImagePicker.toggle()
                                }, label: {
                                    Text("写真を撮影")
                                })
                            }
                        }
                    }
            }
            .navigationBarTitle("Home", displayMode: .inline)
        }
    .ignoresSafeArea(.all, edges: .top)
    .background(Color.primary.opacity(0.06).ignoresSafeArea(.all, edges: .all))
}

IMG_2317.PNG

ファイルのアップロード処理

ではファイルストアへのアップロード処理を解説します。これは アップロード をタップした際に実行します。今回は写真の名前は photo.jpg で固定ですが、好きなものを指定してください。

IMG_2318.PNG

// アップロード用ボタンの表示
Button(action: {
    // NCMBFileを作成
    let file : NCMBFile = NCMBFile(fileName: "photo.jpg")
    // 保存処理の実行
    file.saveInBackground(data: self.imageData, callback: { result in
        // 処理結果の判定
        switch result {
        case .success:
            // 処理がうまくいっていれば、フラグを立てる
            self.uploaded = true
        case let .failure(error):
            // 失敗した場合
            print("保存に失敗しました: \(error)")
            return;
        }
    })
}, label: {
    Text("アップロード")
})
.alert(isPresented: $uploaded, content: {
    // アップロード完了したらアラート
    Alert(title: Text("アップロード完了"), message: Text("写真をアップロードしました"), dismissButton: .default(Text("閉じる")))
})

画像データはNCMBFileのdataに対して、そのまま適用できます。処理は saveInBackground で非同期に処理されますので、結果を受け取ってからステートのフラグを立てることで alert イベントを実行しています。

コードの全体像は次のようになります。

import SwiftUI
import NCMB

struct ContentView: View {
    // 画像データが入ります
    @State var imageData : Data = .init(capacity:0)
    // フォトライブラリまたはカメラの指定が入ります
    @State var source:UIImagePickerController.SourceType = .photoLibrary
    // イメージピッカーの表示/非表示を切り替えます
    @State var isImagePicker = false
    // アップロード状態を管理します
    @State var uploaded = false

    // 表示    
    var body: some View {
            NavigationView{
                VStack(spacing:0){
                        ZStack{
                            // イメージピッカーの表示/非表示用
                            NavigationLink(
                                destination: Imagepicker(show: $isImagePicker, image: $imageData, sourceType: source),
                                isActive:$isImagePicker,
                                label: {
                                    Text("")
                                })
                            VStack{
                                // イメージデータの有無で表示路切り替え
                                if imageData.count != 0{
                                    // イメージデータがある場合
                                    // 画像を表示
                                    Image(uiImage: UIImage(data: self.imageData)!)
                                        .resizable()
                                        .aspectRatio(contentMode: .fill)
                                        .frame(height: 250)
                                        .cornerRadius(15)
                                        .padding()
                                    // アップロード用ボタンの表示
                                    Button(action: {
                                        // NCMBFileを作成
                                        let file : NCMBFile = NCMBFile(fileName: "photo.jpg")
                                        // 保存処理の実行
                                        file.saveInBackground(data: self.imageData, callback: { result in
                                            // 処理結果の判定
                                            switch result {
                                            case .success:
                                                // 処理がうまくいっていれば、フラグを立てる
                                                self.uploaded = true
                                            case let .failure(error):
                                                // 失敗した場合
                                                print("保存に失敗しました: \(error)")
                                                return;
                                            }
                                        })
                                    }, label: {
                                        Text("アップロード")
                                    })
                                    .alert(isPresented: $uploaded, content: {
                                        // アップロード完了したらアラート
                                        Alert(title: Text("アップロード完了"), message: Text("写真をアップロードしました"), dismissButton: .default(Text("閉じる")))
                                    })
                                }
                                // 写真撮影またはフォトライブラリを開くボタン
                                HStack(spacing:30){
                                    // フォトライブラリを開く
                                    Button(action: {
                                        self.source = .photoLibrary
                                        self.isImagePicker.toggle()
                                    }, label: {
                                        Text("フォトライブラリ")
                                    })
                                    // カメラを開く
                                    Button(action: {
                                        self.source = .camera
                                        self.isImagePicker.toggle()
                                    }, label: {
                                        Text("写真を撮影")
                                    })
                                }
                            }
                        }
                }
                .navigationBarTitle("Home", displayMode: .inline)
            }
        .ignoresSafeArea(.all, edges: .top)
        .background(Color.primary.opacity(0.06).ignoresSafeArea(.all, edges: .all))
    }
}

まとめ

写真アプリなど、写真データをクラウドにアップロードしたいという機会は多いかと思います。そうした時にサーバを用意せずに使えるNCMBは、アプリ開発を高速化してくれる良い手段になるはずです。ぜひお使いください!

mBaaSでサーバー開発不要! | ニフクラ mobile backend

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?