質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.76%

MessageKitとFirebaseを用いたチャットアプリについて

受付中

回答 0

投稿

  • 評価
  • クリップ 0
  • VIEW 1,147

shisen-t

score 21

MessageKitを用いてチャットアプリを作ろうと考えています。
こちらを参考にCloud FireStoreを用いながらデータのやり取りができるように進めています。
func updateViewWhenMessageAdded()のところで「unexpectedly found nil while unwrapping an optional value」エラーが出てしまいます。
ここをコメントアウトした時にInputBarに入力したテキストがFirebaseに送られることは確認できたのですが、取り出すことができずチャットのメッセージを見ることができない状態です。
解決の糸口になるページ等ご存知の方がいらっしゃいましたらご教授頂けると幸いです。

class ViewController: MessagesViewController {

    private var ref: Firestore!                                    //Cloud Firestoreの情報を参照
    private var user: User!                                        //ユーザ情報
    private var handle: DatabaseHandle!                            //オブザーバーの破棄を適切にする処理
    var messageList: [Message] = []                                //Message型のオブジェクトの入る配列
    var sendData: [String: Any] = [:]                              //Cloud Firestoreに書き込む内容を格納する辞書
    var readData: [[String: Any]] = []                             //Cloud Firestoreからの読み込み
    var deleteData: [[String: Any]] = []

    let dateFormatter:DateFormatter = DateFormatter()              //日時のフォーマットを管理するもの

    override func viewDidLoad() {
        super.viewDidLoad()

        // データベース読み取り
        self.setupFirebase()

        //データベースを生成して参照情報をインスタンス化
        ref = Firestore.firestore()             //リファレンス(参照)の初期化
        user = Auth.auth().currentUser          //ユーザー認証した現在のユーザーを格納




        //データの扱い
        messagesCollectionView.messagesDataSource = self as MessagesDataSource
        //レイアウト
        messagesCollectionView.messagesLayoutDelegate = self as MessagesLayoutDelegate
        //ディスプレイ
        messagesCollectionView.messagesDisplayDelegate = self as MessagesDisplayDelegate
        //Cellの扱い方
        messagesCollectionView.messageCellDelegate = self as MessageCellDelegate
        //文字入力の部分
        messageInputBar.delegate = self as InputBarAccessoryViewDelegate

        // メッセージ入力が始まった時に一番下までスクロールする
        scrollsToBottomOnKeyboardBeginsEditing = true // default false
        // 表示している画面とキーボードの重複を防ぐ
        maintainPositionOnKeyboardFrameChanged = true // default false

        //DateFormatter()で日付と時刻と地域を指定(今回は日本時間を指定)
        dateFormatter.dateStyle = .medium 
        dateFormatter.timeStyle = .short  
        dateFormatter.locale = Locale(identifier: "ja_JP")

    }


    func setupFirebase() {

        // 最新のデータが追加されるたびに最新データを取得する
        self.updateViewWhenMessageAdded()
    }


    //Cloud Firestoreに書き込みをする際の処理
    func sendMessageToFirebase(text: String){
        if !sendData.isEmpty {sendData = [:] } //辞書の初期化(送信データの中身がからじゃなければ空にする)


        let sendRef = ref.collection("chats").addDocument(data: ["senderName": user?.displayName,//送信者の名前
            "senderId": user?.uid,          //送信者のID
            "content": text,                //送信内容(今回は文字のみ)

            "createdAt": dateFormatter.string(from: Date()),//送信時刻
            "messageId": messageList //送信メッセージのID
            ])

    }


    //データベースから読み込んだデータを配列(readData)に格納するメソッド
    func snapshotToArray(snapshot: DataSnapshot){
        //中身を0にする
        if !readData.isEmpty {readData = [] }
        //スナップショットとは、ある時点における特定のデータベース参照にあるデータの全体像を写し取ったもの
        if snapshot.children.allObjects as? [DataSnapshot] != nil  {
            let snapChildren = snapshot.children.allObjects as? [DataSnapshot]
            //snapChildrenの中身の数だけsnapChildをとりだす
            for snapChild in snapChildren! {
                //要素を追加していく
                //snapChildのvalueに値があったらreadDataに追加していく
                if let postDict = snapChild.value as? [String: Any] {
                    self.readData.append(postDict)
                }
            }
        }
    }

    //メッセージの画面表示に関するメソッド
    func displayMessageHuman() {
        //メッセージリストを初期化
        if !messageList.isEmpty {messageList = []}

        for itemHuman in readData {
            print("Humanitem: \(itemHuman)\n")
            let message = Message(
                sender: Sender(id: itemHuman["senderId"] as! String,displayName: itemHuman["senderName"] as! String),
                messageId: itemHuman["messageId"] as! String,
                sentDate: self.dateFormatter.date(from: itemHuman["createdAt"] as! String)!,
                kind: MessageKind.text(itemHuman["content"] as! String)
            )
            messageList.append(message)
        }
    }

    //メッセージが追加された際に読み込んで画面を更新するメソッド
    func updateViewWhenMessageAdded() {
        ref.collection("chats").addSnapshotListener{(snapShot, error) in
            if let err = error {
                print("Error getting documents: \(err)")
            } else {
                for document in snapShot!.documents {
                    print("\(document.documentID) => \(document.data())")
                }
            }
//            value.documentChanges.forEach {
//                diff in
//                if (diff.type == .added) {
//                    print("New city: \(diff.document.data())")
//                    let snapshotValue = diff.document.data()
//                    let text = snapshotValue["text"] as! String
//                    let name = snapshotValue["name"] as! String
//                    let date = snapshotValue["timestamp"] as! Date
//                 self.messageList.append(self.sendMessageToFirebase(text: text, sender: name, name: name, date: date))
//                }
//                if (diff.type == .modified) {
//                    print("Modified city: \(diff.document.data())")
//                }
//                if (diff.type == .removed) {
//                    print("Removed city: \(diff.document.data())")
//                }
//            }
        }

        messagesCollectionView.reloadData()
        messagesCollectionView.scrollToBottom()

        self.messageList.reverse()

    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationController?.setNavigationBarHidden(false, animated: false)
    }

    override func viewDidAppear(_ animated: Bool) {
        self.becomeFirstResponder() // inputバーを再表示
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}


字数制限のため拡張部分のコードは省いています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.76%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る