1
1

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.

【NCMBハンズオン】Swift SDKを使ってTodoアプリを作ろう

Last updated at Posted at 2021-05-21
1 / 35

必要なもの

  • Xcode
  • Ruby
  • CocoaPods
  • NCMBのアカウント

ベースアプリについて

ベースアプリはNCMBMania/Swift_Todo_Handsonになります。まずGitリポジトリをクローンしてください。

git clone git@github.com:NCMBMania/Swift_Todo_Handson.git

Swift SDKの導入について

該当リポジトリにはすでに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

CocoaPodsのインストールはターミナルで次のように実行します。

$ gem install cocoapods

NCMB SDKをCocoaPodsでインストールします。

$ pod install

todoappApp.swiftの編集

todoappApp.swiftはアプリが立ち上がった際の初期設定を行います。まずNCMB SDKを読み込みます。

import NCMB

SDKの初期化

// NCMBの初期化処理をここに書きます 以下に記述していきます。


SDKを初期化します。アプリケーションキー、クライアントキーはあらかじめ取得してください。

// アプリがアクティブになったタイミングでNCMBを初期化
NCMB.initialize(applicationKey: "YOUR_APPLICATION_KEY", clientKey: "YOUR_CLIENT_KEY")

匿名認証を有効にする

NCMBの管理画面にて、匿名認証を有効にしてください。

image.png


さらにSwift SDKで匿名認証を有効にします。

// 匿名認証を有効にする
NCMBUser.enableAutomaticUser()

ログインユーザを取得する

現在ログインしているユーザの情報を取得します。

// 現在ログインしているかチェック
let user = NCMBUser.currentUser

認証状態のチェック

user が nil かどうかで判定します

if user == nil {
    // ログインしていない場合
} else {
    // ログインしている場合
}

ログインしていない場合

ログインしていない場合は匿名認証を行います。

// 匿名認証を実施
NCMBUser.automaticCurrentUserInBackground(callback: { result in
    // 認証結果の判定
    switch result {
            case .success:
                // ログインに成功した場合の処理
                print("匿名ユーザーでのログインに成功しました")
            case let .failure(error):
                // ログインに失敗した場合の処理
                print("匿名ユーザーでのログインに失敗しました: \(error)")
        }
})

認証している場合

認証している場合はセッションの有効性チェックを行います。エラーだった場合はログアウトします。

// セッションの有効性チェック
// 適当なデータストア(今回はTodoクラス)にアクセス
var query : NCMBQuery<NCMBObject> = NCMBQuery.getQuery(className: "Todo")
query.limit = 1 // レスポンス件数を最小限にする
// アクセス
query.findInBackground(callback: { results in
    // 結果の判定
    switch results {
    case let .success(obj):
        // 返ってくれば問題なし
        print(obj)
    case let .failure(error):
        // エラーの場合は強制ログアウト
        NCMBUser.logOutInBackground(callback: { result in
            print("強制ログアウト")
        })
    }
})

ContentView.swiftの修正

ContentViewにはアプリの実装を行います。


ContentViewの実装内容

以下の画面があります。

  • 一覧画面
  • タスク追加画面
  • タスク編集画面

一覧画面

一覧画面ではタスクを取得して一覧表示、さらに一覧からタスクの削除を行います。

// 記述済み
struct ContentView /* 省略 */

タスク追加画面

タスク追加画面では新しいタスクの名前を入力します。

// 記述済み
struct InputView: View {
}

タスク編集画面

タスク編集画面では一覧画面で選択されたタスクを表示、編集します。

// 記述済み
struct EditView: View {
}

SDKの読み込み

ContentView.swiftでもNCMB SDKを読み込みます。

import NCMB

ObservableObjectの用意

タスク一覧を管理するObservableObjectを用意します。

// NCMBObjectを直接設定できないので ObservableObject を経由させます
class Todos: ObservableObject {
    @Published var todos: [NCMBObject] = []
}

ObservableObjectをContentViewの中で読み込みます。

struct ContentView: View, InputViewDelegate, EditViewDelegate {
    // ObservedObjectとして定義します
    @ObservedObject var Todo = Todos()

追加画面への遷移

メイン画面で Add ボタンをタップすると追加画面に遷移します。

// 記述済み
NavigationLink(destination: InputView(delegate: self, text: "")) {
    Text("Add")
        .foregroundColor(Color.white)
        .font(Font.system(size: 20))
}

NCMBの追加処理

タスク追加画面で追加ボタンをタップすると、Delegateを通じて ContentViewの addTodo が呼び出されます。

// タスクの追加処理です
func addTodo(text: String) {
    // 新しいタスクオブジェクトを作成します
    let obj = NCMBObject(className: "Todo")
    // 入力された文字列を適用します
    obj["body"] = text
    // ACL(アクセス権限)を作成します
    var acl = NCMBACL.empty
    // 現在のログインユーザを取得します
    let user = NCMBUser.currentUser!
    // ログインユーザに対して読み込み、書き込み権限を付与します
    acl.put(key: user.objectId!, readable: true, writable: true)
    // ついでにAdminグループに対して読み込み、書き込み権限を付与する例です
    acl.put(key: "role:Admin", readable: true, writable: false)
    // ACLを適用します
    obj.acl = acl
    // 保存します
    obj.saveInBackground(callback: { result in
        // 保存結果の判定
        switch result {
            // 保存成功
            case .success(_):
                // 画面に反映させるのでメインスレッドに戻します
                DispatchQueue.main.async {
                  // Todoに新しいタスクを追加
                  self.Todo.todos.append(obj)
                  self.Todo.objectWillChange.send()
                }
            // 保存失敗
            case let .failure(error):
                print("作成に失敗しました: \(error)")
        }
    })
}

一覧画面の作成

ContentViewのZStack.onAppearの中で、画面表示時にTodoクラスからデータを取得し、Todoに対してデータをセットします。


以下の中に記述します。

// 記述済み
.onAppear {
    // 画面表示された際のイベントです
}

記述内容です。

// Todoクラス用のクエリを用意します
let query : NCMBQuery<NCMBObject> = NCMBQuery.getQuery(className: "Todo")
// 検索処理を実行します
// 処理は非同期です
query.findInBackground(callback: { result in
    // 結果の判定です
    switch result {
        // 取得できた場合
        case let .success(array):
            // メインスレッドなので main.async を使います
            DispatchQueue.main.async {
                // 結果を適用します
                self.Todo.todos = array
            }
        // 取得失敗した場合
        case let .failure(error):
            print("取得に失敗しました: \(error)")
    }
})

一覧表示

一覧表示は以下のコード内に記述します。

// 記述済み
List {
    // Todo変数のデータを一覧表示します
}

記述内容です。タップした際に編集画面に遷移する処理も加えています。

// Todo変数のデータを一覧表示します
ForEach(self.Todo.todos, id: \.objectId) { todo in
    // todoはNCMBObjectです
    // タスク文字列をタップしたらEditViewを呼び出します
    NavigationLink(destination: EditView(delegate: self, objectId: todo.objectId!, text: (todo["body"] ?? "") as String)) {
        Text((todo["body"] ?? "") as String)
    }
}
// 削除イベントでdeleteを呼び出します
.onDelete(perform: delete)

タスクの削除

一覧画面での onDelete イベントで ContentView.delete を呼び出しています。


記述は次のようになります。

// タスクの削除処理です
func delete(at offsets: IndexSet) {
    // 処理対象のタスクを取得します
    let todo = self.Todo.todos[Array(offsets)[0]] as NCMBObject
    // 削除を実行します(同期処理にしていますが非同期でも可)
    let result = todo.delete()
    // 処理結果の判定です
    switch result {
        // 成功した場合
        case .success(_):
            // Todoから該当のタスクを削除します
            self.Todo.todos.remove(atOffsets: offsets)
        // 失敗した場合
        case let .failure(error):
            print(error)
    }
}

タスク編集処理

タスク編集画面で編集ボタンをタップすると、Delegateを通じて ContentView.editTodo が呼び出されます。


内容は次のようになります。

// タスクの編集処理です
func editTodo(text: String, objectId: String) {
    // 処理対象のタスクを特定します
    if let i = self.Todo.todos.firstIndex(where: { $0.objectId == objectId}) {
        let obj = self.Todo.todos[i]
        // 新しい本文を適用
        obj["body"] = text
        // 更新します
        obj.saveInBackground(callback: { result in
            // 更新結果の判定
            switch result {
                // 更新成功
                case .success(_):
                    // 画面に反映させるのでメインスレッドに戻します
                    DispatchQueue.main.async {
                      // Todoを書き換えます
                      self.Todo.todos[i] = obj
                      self.Todo.objectWillChange.send()
                    }
                // 更新失敗
                case let .failure(error):
                    print("更新に失敗しました: \(error)")
            }
        })
    }
}

まとめ

今回のハンズオンでは次の3つの機能を利用しました。

  • 会員管理
    • 匿名認証
  • データストア登録/更新/削除
  • データストア検索
1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?