🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

991閲覧

MessageKitで「Invalid update: invalid number of sections. 」エラーが出てしまう

yotubarail

総合スコア23

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

1グッド

0クリップ

投稿2019/11/13 07:17

MessageKitとFirestoreを用いてチャットアプリを作ってみようと考えています。
Firestoreとデータを送受信できるようにしたいのですが、Firestoreにデータを送ったあと「Invalid update: invalid number of sections. 」とエラーが出てしまいました。
sendMessageToFirebase(text: text)をコメントアウトし、Firestoreにデータを送信しないようにするとmessageInputBarに入力した文字が画面上に表示されます。
UICollectionViewのセクション数の問題であるのはわかるのですが、Firestoreに送るかどうかでなぜこのような違いが出ているのかわからずにいます。

解決の糸口となりそうなものをお分かりになる方がいらっしゃいましたら、ご教授頂けると幸いです。

Swift

1class ViewController: MessagesViewController { 2 3 let chatCnt: Int = 100 4 var messageList: [MockMessage] = [] 5 6 var database: Firestore! 7 8 9 let dateFormatter:DateFormatter = DateFormatter() //日時のフォーマットを管理するもの 10 11 lazy var formatter: DateFormatter = { 12 let formatter = DateFormatter() 13 formatter.dateStyle = .medium 14 return formatter 15 }() 16 17 override func viewDidLoad() { 18 super.viewDidLoad() 19 print("App open") 20 21 database = Firestore.firestore() 22 23 24 25 //Firestoreからデータを取得し、TextViewに表示する 26 self.database.collection("chat").order(by: "timestamp", descending: true).limit(to: self.chatCnt + 25).addSnapshotListener { (snapShot, error) in 27 guard snapShot != nil else { 28 print("snapShot is nil") 29 return 30 } 31 32 snapShot!.documentChanges.forEach{diff in 33 //更新内容が追加だったときの処理 34 if diff.type == .added { 35 //追加データを変数に入れる 36 let chatDataOp = diff.document.data() as? Dictionary<String, String> 37 print(diff.document.data()) 38 guard let chatData = chatDataOp else { 39 return 40 } 41 guard chatData["content"] != nil else { 42 return 43 } 44 guard chatData["senderName"] != nil else { 45 return 46 } 47 //TextViewの一番下に新しいメッセージ内容を追加する 48 self.messageList = self.getMessages() 49 } 50 } 51 } 52 53 54 DispatchQueue.main.async { 55 // messageListにメッセージの配列をいれて 56 self.messageList = self.getMessages() 57 // messagesCollectionViewをリロードして 58 self.messagesCollectionView.reloadData() 59 // 一番下までスクロールする 60 self.messagesCollectionView.scrollToBottom() 61 } 62 63 messagesCollectionView.messagesDataSource = self 64 messagesCollectionView.messagesLayoutDelegate = self 65 messagesCollectionView.messagesDisplayDelegate = self 66 messagesCollectionView.messageCellDelegate = self 67 68 messageInputBar.delegate = self 69 messageInputBar.sendButton.tintColor = UIColor.lightGray 70 71 72 73 // メッセージ入力時に一番下までスクロール 74 scrollsToBottomOnKeyboardBeginsEditing = true // default false 75 maintainPositionOnKeyboardFrameChanged = true // default false 76 77 //DateFormatter()で日付と時刻と地域を指定(今回は日本時間を指定) 78 dateFormatter.dateStyle = .medium //日付の表示スタイルを決定 79 dateFormatter.timeStyle = .short //時刻の表示スタイルを決定 80 dateFormatter.locale = Locale(identifier: "ja_JP")//地域を決定 81 } 82 83 84 85 86 87 //Cloud Firestoreに書き込みをする際の処理 88 //Firebaseにチャット内容を保存するためのメソッド 89 //Firebaseに送りたい情報は今回はテキスト 90 func sendMessageToFirebase(text: String){ 91 if !messageList.isEmpty {messageList = [] } //辞書の初期化(送信データの中身がからじゃなければ空にする) 92 93 //これがJSON(書き方のルール的な) 94 _ = database.collection("message").addDocument(data: [ 95 "senderName": "takinami",//送信者の名前 96 "content": text, //送信内容(今回は文字のみ) 97 98 "createdAt": dateFormatter.string(from: Date()),//送信時刻 99 "messageId": messageList //送信メッセージのID 100 ]) 101 102 } 103 104 // サンプル用に適当なメッセージ 105 func getMessages() -> [MockMessage] { 106 return [ 107 createMessage(text: "String") 108 ] 109 } 110 111 func createMessage(text: String) -> MockMessage { 112 let attributedText = NSAttributedString(string: text, attributes: [.font: UIFont.systemFont(ofSize: 15), 113 .foregroundColor: UIColor.black]) 114 return MockMessage(attributedText: attributedText, sender: otherSender(), messageId: UUID().uuidString, date: Date()) 115 } 116 117 override func didReceiveMemoryWarning() { 118 super.didReceiveMemoryWarning() 119 } 120} 121 122extension ViewController: MessagesDataSource { 123 124 func currentSender() -> SenderType { 125 return Sender(id: "123", displayName: "自分") 126 } 127 128 func otherSender() -> Sender { 129 return Sender(id: "456", displayName: "知らない人") 130 } 131 132 func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { 133 return messageList.count 134 } 135 136 func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType { 137 return messageList[indexPath.section] 138 } 139 140 // メッセージの上に文字を表示 141 func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? { 142 if indexPath.section % 3 == 0 { 143 return NSAttributedString( 144 string: MessageKitDateFormatter.shared.string(from: message.sentDate), 145 attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 10), 146 NSAttributedString.Key.foregroundColor: UIColor.darkGray] 147 ) 148 } 149 return nil 150 } 151 152 // メッセージの上に文字を表示(名前) 153 func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? { 154 let name = message.sender.displayName 155 return NSAttributedString(string: name, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption1)]) 156 } 157 158 // メッセージの下に文字を表示(日付) 159 func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? { 160 let dateString = formatter.string(from: message.sentDate) 161 return NSAttributedString(string: dateString, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption2)]) 162 } 163} 164 165// メッセージのdelegate 166extension ViewController: MessagesDisplayDelegate { 167 168 // メッセージの色を変更(デフォルトは自分:白、相手:黒) 169 func textColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor { 170 return isFromCurrentSender(message: message) ? .white : .darkText 171 } 172 173 // メッセージの背景色を変更している(デフォルトは自分:緑、相手:グレー) 174 func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor { 175 return isFromCurrentSender(message: message) ? 176 UIColor(red: 69/255, green: 193/255, blue: 89/255, alpha: 1) : 177 UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1) 178 } 179 180 // メッセージの枠にしっぽを付ける 181 func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle { 182 let corner: MessageStyle.TailCorner = isFromCurrentSender(message: message) ? .bottomRight : .bottomLeft 183 return .bubbleTail(corner, .curved) 184 } 185 186 // アイコンをセット 187 func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) { 188 // message.sender.displayNameとかで送信者の名前を取得できるので 189 // そこからイニシャルを生成するとよい 190 let avatar = Avatar(initials: "人") 191 avatarView.set(avatar: avatar) 192 } 193} 194 195 196// 各ラベルの高さを設定(デフォルト0なので必須) 197extension ViewController: MessagesLayoutDelegate { 198 199 func cellTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat { 200 if indexPath.section % 3 == 0 { return 10 } 201 return 0 202 } 203 204 func messageTopLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat { 205 return 16 206 } 207 208 func messageBottomLabelHeight(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGFloat { 209 return 16 210 } 211} 212 213extension ViewController: MessageCellDelegate { 214 // メッセージをタップした時の挙動 215 func didTapMessage(in cell: MessageCollectionViewCell) { 216 print("Message tapped") 217 } 218} 219 220extension ViewController: MessageInputBarDelegate { 221 // メッセージ送信ボタンをタップした時の挙動 222 func inputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String) { 223 224 225 for _ in inputBar.inputTextView.components { 226 227 let attributedText = NSAttributedString(string: text, attributes: [.font: UIFont.systemFont(ofSize: 15), 228 .foregroundColor: UIColor.white]) 229 let message = MockMessage(attributedText: attributedText, sender: currentSender(), messageId: UUID().uuidString, date: Date()) 230 messageList.append(message) 231 messagesCollectionView.insertSections([messageList.count - 1]) 232 } 233 234 235 236 //Firebaseに送信するメソッド 237 sendMessageToFirebase(text: text) 238 239 240 //inputBarの中のテキストを表示して 241 inputBar.inputTextView.text = String() 242 243 244 //一番下までスクロールしている 245 messagesCollectionView.scrollToBottom() 246 247 print("messageList when sendButton pressed:(messageList)") 248 } 249} 250 251
Hyperbolic4183👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

firebaseのsnapShotを利用しているのに、手動でもmessageListにtextを追加しているから?

投稿2019/11/17 14:19

編集2019/11/17 14:20
smapira

総合スコア33

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yotubarail

2019/11/18 07:48

回答ありがとうございます。 おそらくおっしゃる通りなのですが、func getMessages()をどのように変えれば良いのかをわかっていないため自分で色々試してみようと思います。
yotubarail

2019/11/18 08:14

ありがとうございます!
guest

0

if !messageList.isEmpty {messageList = [] }

が入っているからでは???

投稿2019/11/13 07:50

takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yotubarail

2019/11/13 08:18

回答ありがとうございます。 該当部分をコメントアウトし、再チャレンジしたところ 「'Unsupported type: __SwiftValue'」エラーが出てしまいました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問