コード含め長文な相談となりますが、ご回答いただけますと幸いです。
前提・実現したいこと
■アプリ概要
・チャットアプリ
・FirebaseAuthでユーザー登録(メールアドレス・パスワード)
・Firestoreを利用してチャットルームやチャットルーム内のメッセージデータを管理
■実現したいこと
チャットルーム内のメッセージが、「自分のメッセージ」「相手のメッセージ」に分けて正常に表示されるようにしたい
発生している問題・エラーメッセージ
「すでに他のユーザーが送信したメッセージが存在するチャットルーム」にて、自分のメッセージを送信すると、ランダムで既存のメッセージが非表示になっていき、何度もそれを繰り返すとやがてすべてのメッセージが非表示となる
該当のソースコード
文字数上限を超えてしまうため、追記いたします。
試したこと
db.collection("room").document(roomName).collection("messages").order(by: "date").addSnapshotListener
・上記で取得したメッセージデータを、for文を使ってMessage型の配列へ追加し、Message型の配列の数をPrint > 正常
・Firestore上ではメッセージデータが正常に反映されていることを確認
・cellForRowAtで構築するメッセージの情報(bodyやtimeStamp、isHiddenの状態など)をすべてPrint > 正常
・新規チャットルーム(仮名:TestRoomA)を作成 > TestRoomA内でメッセージを送信 > 何通送信しても正常に反映(表示)される
・ログアウト > 新規アカウント(別アカウント)作成 > TestRoomAを開く > 上記で送信したメッセージは相手からのメッセージとして表示されているが、ここでメッセージを送信すると、送信する度ランダムに相手からのメッセージが非表示になっていき、やがて自分のメッセージ含めすべてのメッセージがそのチャット画面から非表示になる
※メッセージのデータはFirestore上に残ったままであるため、メッセージが「消える」ではなく「非表示になる」という表現を使っております
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
macOS 11.2.3 Xcode 12.3 iOS 14.3(Simulator) ※手持ちのiPhoneはmacに認識されないため、Simulatorのみで検証しております メッセージのセルはカスタムセルを使用しているため、カスタムセルの画像も添付致します。![イメージ説明](9becfb1f8b0371a532cca86420f98d22.png)
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
cellForRowAt の中で isHidden = true にしたものを false に戻してないのが原因ですね。TableView のセルは再利用されるので、他の人のメッセージ表示するために使われたセルが自分のメッセージを表示するために再利用されたり、その逆が起こる可能性があり、そのたびに非表示のものが増えていくと思います。
swift
1 if message.sender == Auth.auth().currentUser?.uid{ 2 3 print("自分のメッセージ: (message.body)") 4 cell.partnersNameLabel.isHidden = true 5 cell.partnersImageView.isHidden = true 6 cell.partnersMessageTextView.isHidden = true 7 cell.timestampByPartner.isHidden = true 8 9 }else{ 10 11 print("相手のメッセージ: (message.body)") 12 cell.myMessageTextView.isHidden = true 13 cell.timestampByMyself.isHidden = true 14 15 }
または、自分と他の人のメッセージ表示するセルはクラスや xib ファイルを分けてもいいかも…。
投稿2021/05/10 13:39
編集2021/05/10 13:40総合スコア7901
0
該当のコードは下記となります。
①チャット画面のコード
Swift
1// 2// RoomViewController.swift 3// SimpleDiscussionApp 4// 5 6import UIKit 7import Firebase 8import FirebaseFirestore 9import SDWebImage 10 11class ChatViewController: UIViewController,UITextFieldDelegate,UITableViewDelegate,UITableViewDataSource { 12 13 @IBOutlet weak var tableView: UITableView! 14 @IBOutlet weak var messageTextField: UITextField! 15 @IBOutlet weak var roomImageView: UIImageView! 16 @IBOutlet weak var sendButton: UIButton! 17 18 let db = Firestore.firestore() 19 var roomName = String() 20 var userName = String() 21 var userImageString = String() 22 var roomImageString = String() 23 var messages = [Message]() 24 25 override func viewDidLoad() { 26 super.viewDidLoad() 27 28 tableView.delegate = self 29 tableView.dataSource = self 30 messageTextField.delegate = self 31 //Cell(xib)の情報を呼び出す 32 tableView.register(UINib(nibName: "MessageCell", bundle: nil), forCellReuseIdentifier: "MessageCell") 33 //userImage(icon)とuserNameを取り出しておく 34 if let savedUserImageString = UserDefaults.standard.object(forKey: "iconImage") as? String, 35 let userName = UserDefaults.standard.object(forKey: "userName") as? String{ 36 37 self.userImageString = savedUserImageString 38 self.userName = userName 39 40 } 41 42 } 43 44 override func viewWillAppear(_ animated: Bool) { 45 super.viewWillAppear(animated) 46 47 loadMessages(roomName: roomName) 48 roomImageView.sd_setImage(with: URL(string: roomImageString), completed: nil) 49 navigationController?.isNavigationBarHidden = false 50 sendButton.isEnabled = false 51 sendButton.layer.masksToBounds = true 52 sendButton.layer.cornerRadius = 25 53 54 } 55 56 //ルームデータの取得------------------------------------ 57 func loadMessages(roomName:String){ 58 59 //メッセージ 60 db.collection("room").document(roomName).collection("messages").order(by: "date").addSnapshotListener { (snapShot, error) in 61 62 self.messages = [] 63 print("⓪メッセージの配列を空にしておきます") 64 var timeStamp = String() 65 let dateFormatter = DateFormatter() 66 dateFormatter.dateFormat = "HH:mm" 67 68 if error != nil{ 69 70 print("error: " + error.debugDescription) 71 return 72 } 73 74 if let snapShotDoc = snapShot?.documents{ 75 76 for doc in snapShotDoc{ 77 78 let data = doc.data() 79 if let sender = data["sender"] as? String, 80 let userName = data["userName"] as? String, 81 let body = data["body"] as? String, 82 let userImageString = data["userImageString"] as? String, 83 let date = data["date"] as? Timestamp{ 84 85 let time = date.dateValue() 86 timeStamp = dateFormatter.string(from: time) 87 let newMessage = Message(sender: sender, userName: userName, body: body, userimageString: userImageString, timeStamp: timeStamp) 88 89 self.messages.append(newMessage) 90 print("①取得したメッセージ件数分、配列へ追加します") 91 92 } 93 94 } 95 96 print("メッセージ件数: " + String(self.messages.count)) 97 self.tableView.reloadData() 98 print("③tableViewのデータをリロードします") 99 if self.messages.count > 0{ 100 //[0]からカウントのため、rowが10あれば[0~9]と数えるので、self.messages.count - 1 と記述 101 let indexPath = IndexPath(row: self.messages.count - 1, section: 0) 102 //送信したメッセージの箇所まで自動的にスクロールする 103 self.tableView.scrollToRow(at: indexPath, at: .top, animated: true) 104 105 } 106 107 } 108 109 } 110 111 } 112 113 //tableView------------------------------------ 114 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 115 return messages.count 116 } 117 118 func numberOfSections(in tableView: UITableView) -> Int { 119 return 1 120 } 121 122 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 123 124 print("④配列にある数だけ、セルを構築します((messages.count)件)") 125 let cell = tableView.dequeueReusableCell(withIdentifier: "MessageCell", for: indexPath) as! MessageCell 126 let message = messages[indexPath.row] 127 128 if message.sender == Auth.auth().currentUser?.uid{ 129 130 print("自分のメッセージ: (message.body)") 131 print("⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤") 132 cell.myMessageTextView.text = message.body 133 print(cell.myMessageTextView.text!) 134 cell.timestampByMyself.text = message.timeStamp 135 print(cell.timestampByMyself.text!) 136 cell.partnersNameLabel.isHidden = true 137 print(cell.partnersNameLabel.isHidden) 138 cell.partnersImageView.isHidden = true 139 print(cell.partnersImageView.isHidden) 140 cell.partnersMessageTextView.isHidden = true 141 print(cell.partnersMessageTextView.isHidden) 142 cell.timestampByPartner.isHidden = true 143 print(cell.timestampByPartner.isHidden) 144 print("⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤") 145 146 }else{ 147 148 print("相手のメッセージ: (message.body)") 149 print("⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤") 150 cell.partnersMessageTextView.text = message.body 151 print(cell.partnersMessageTextView.text!) 152 cell.partnersNameLabel.text = message.userName 153 print(cell.partnersNameLabel.text!) 154 cell.timestampByPartner.text = message.timeStamp 155 print(cell.timestampByPartner.text!) 156 cell.partnersImageView.sd_setImage(with: URL(string: messages[indexPath.row].userimageString), completed: nil) 157 cell.myMessageTextView.isHidden = true 158 print(cell.myMessageTextView.isHidden) 159 cell.timestampByMyself.isHidden = true 160 print(cell.timestampByMyself.isHidden) 161 if let image = cell.partnersImageView.image{ 162 163 print(image) 164 165 } 166 print("⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤⏤") 167 168 } 169 170 return cell 171 } 172 173 174 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 175 return UITableView.automaticDimension 176 } 177 178 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 179 180 if textField.text != nil{ 181 182 sendButton.isEnabled = true 183 184 } 185 186 return true 187 } 188 //メッセージの送信------------------------------------ 189 @IBAction func sendAction(_ sender: Any) { 190 191 if let messageBody = messageTextField.text, 192 let sender = Auth.auth().currentUser?.uid{ 193 194 let timeInterval = Date().timeIntervalSince1970 195 let sendTimeInterval = TimeInterval(timeInterval) 196 let time = Date(timeIntervalSince1970: TimeInterval(sendTimeInterval)) 197 let userName = self.userName 198 199 db.collection("room").document(roomName).collection("messages").addDocument(data: [ 200 201 "sender":sender,"userName":userName,"body":messageBody,"userImageString":self.userImageString,"date":time 202 203 ]) { (error) in 204 205 if error != nil{ 206 207 print("error: " + error.debugDescription) 208 return 209 210 } 211 212 self.messageTextField.text = "" 213 self.messageTextField.resignFirstResponder() 214 215 } 216 217 db.collection("room").document(roomName).updateData(["latestMessage":messageBody], completion: { (error) in 218 219 if error != nil{ 220 221 print("error: " + error.debugDescription) 222 return 223 224 } 225 226 }) 227 228 } 229 } 230 231 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 232 233 messageTextField.resignFirstResponder() 234 235 } 236 237 func textFieldShouldReturn(_ textField: UITextField) -> Bool { 238 239 messageTextField.resignFirstResponder() 240 241 } 242 243} 244
投稿2021/05/09 15:05
総合スコア5
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/05/09 23:10
2021/05/09 23:15
2021/05/09 23:18
2021/05/10 10:33
2021/05/10 10:42
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。