LoginSignup
0
1

More than 1 year has passed since last update.

NCMBのSwift SDKとWebSocketを使ってチャットアプリを作る(その2:メッセージの送信とデータストアへの保存)

Last updated at Posted at 2021-09-08

ハンズオン開催

こちらの内容を元にオンラインハンズオンを開催します。1時間程度になりますので、ご興味があればぜひご参加ください。

NCMBのSwift SDKを使ってデモアプリを作ってみます。リアルタイム通信系は人気があるのですが、NCMBでは残念ながらWebSocketは使えません。そこで今回はPieSocketというWebSocketを提供するサービスと組み合わせて、Swift製のチャットアプリを作ってみます。

前回は仕様と画面の説明、Swift SDKの初期化までを説明しました。今回はチャットメッセージの送信について解説します。

コードについて

今回のコードはNCMBMania/Swift_Chat_Demoにアップロードしてあります。実装時の参考にしてください。

チャットメッセージの送信

フローは次のようになります。

  • NCMBのデータストアにチャットメッセージを保存する
  • WebSocketでメッセージを送信する

NCMBのデータストアにチャットメッセージを保存する

入力されたテキストと、ログインユーザの情報を紐付けてNCMBに保存します。これは ChatInputView の send メソッドに実装します。注意点としてはACLを使ってアクセスコントロールを設定しているところでしょうか。

// チャットメッセージを送信する関数
func send() {
    // NCMBのデータストア用のオブジェクトを用意
    let obj = NCMBObject(className: "Chat")
    // 必要なデータを設定
    obj["body"] = message
    let user = NCMBUser.currentUser
    obj["userId"] = user!.objectId
    var acl = NCMBACL.empty // ACL(アクセス管理)を定義
    // * = 全員。読み込み可能、編集不可
    acl.put(key: "*", readable: true, writable: false)
    // ユーザのobjectId。指定したユーザ(投稿者)のみ読み込み可能、編集可能
    acl.put(key: user!.objectId!, readable: true, writable: true)
    obj.acl = acl // ACLを設定
    // 表示名も設定
    if let displayName: String = user!["displayName"] {
        obj["displayName"] = displayName
    }
    _ = obj.save()       // 保存
    message = ""         // 入力されていたメッセージを消す
    chat.send(obj: obj)  // WebSocketで送信
}

WebSocketでメッセージを送信する

保存後、WebSocketでメッセージを送信します。WebSocketでは基本的にテキストメッセージを送信するので、NCMBObjectから必要なデータを取り出して、JSONテキストに変換します。これは ChatScreenModel の makeMessage メソッドで行います。

// チャットメッセージを送信する関数
func send(obj: NCMBObject) {
    // NCMBObjectからメッセージを作成して、送信
    webSocketTask?.send(.string(makeMessage(obj: obj)), completionHandler: { error in
        if error != nil {
            // エラーの場合
            print(error)
        }
    })
}

makeMessage は必要な情報を集めてDictionaryを作成し、それをJSONテキスト化します。日付だけISO8601形式に変換して入れています。

// NCMBObjectをDictionaryにして、JSON文字列にする関数
private func makeMessage(obj: NCMBObject) -> String {
    // Dictionaryの準備
    var json = Dictionary<String, String>()
    json["objectId"] = obj.objectId! // チャットメッセージのobjectId
    json["body"] = obj["body"] ?? "" // チャットメッセージ
    json["userId"] = obj["userId"] ?? "" // チャットの送信者
    json["displayName"] = obj["displayName"] ?? "" // チャットの表示名
    // 投稿日時
    let formatter = ISO8601DateFormatter()
    json["createDate"] = formatter.string(from: Date())
    do {
        // Dictionaryを文字列化
        let jsonData = try JSONSerialization.data(withJSONObject: json)
        return String(bytes: jsonData, encoding: .utf8)!
    } catch (let e) {
        print(e)
    }
    return "" // エラーの場合
}

WebSocketでメッセージを送信すると受信時のハンドラである onReceive メソッドが呼ばれます。ここでは送信時と逆に、受け取ったメッセージを分解してNCMBObjectオブジェクトを作成します。なお、URLSessionWebSocketTaskではメッセージを1度しか受信してくれないので、最後にもう一度受信時のハンドラを設定しておきます。

// メッセージを受け取った時に呼ばれる関数
private func onReceive(incoming: Result<URLSessionWebSocketTask.Message, Error>) {
    switch incoming {
    case let .success(message): // 正しく受け取れている場合
        // メッセージの種類に応じて処理分け(今回はテキストのみ)
        switch message {
        case let .string(msg):
            // テキストをデータ化
            let data: Data =  msg.data(using: String.Encoding.utf8)!
            do {
                // JSONとしてパース
                let params = try JSONSerialization.jsonObject(with: data) as! Dictionary<String, String>
                // NCMBObjectとして作り直し
                let obj = NCMBObject(className: "Chat")
                obj["displayName"] = params["displayName"]
                obj.objectId = params["objectId"]
                obj["userId"] = params["userId"]
                obj["body"] = params["body"]
                obj["createDate"] = params["createDate"]
                DispatchQueue.main.async {
                    self.messages.append(obj) // メッセージの配列に追加
                }
            } catch {
            }
            break
        case let .data(data):
            print(data)
        @unknown default:
            print("unknown \(message)")
        }
        break
    case let .failure(err):
        print(err)
        break
    }
    webSocketTask?.receive(completionHandler: onReceive)
}

これでメッセージの送信処理が完了します。

まとめ

今回はチャットメッセージの送信と、NCMBのデータストアへの保存について解説しました。次回はチャットメッセージの表示と、過去のメッセージを取得する部分を解説します。

0
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
0
1