ニフクラ 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 {
最後に WindowGroup
に onChange
を追加します。この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))
}
ファイルのアップロード処理
ではファイルストアへのアップロード処理を解説します。これは アップロード
をタップした際に実行します。今回は写真の名前は photo.jpg
で固定ですが、好きなものを指定してください。
// アップロード用ボタンの表示
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は、アプリ開発を高速化してくれる良い手段になるはずです。ぜひお使いください!