MessageKitとFirestoreを用いて簡単なチャットアプリを作ろうとしています。
このページを参考に進めてビルドするところまでいったのですが、func loadChat()内の
if (chat?.users.contains(self.user2UID!))! {
の部分で
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x100c3c148)
というエラーが出てしまいます。
コンソールに"No messages to display"というメッセージは出ているので、チャット画面に表示するデータがないのは読み取れているようです。
理由や解決方法をご教授いただけますか。
コード全体は以下の通りです。
swift
1import UIKit 2import InputBarAccessoryView 3import Firebase 4import MessageKit 5import FirebaseFirestore 6import SDWebImage 7 8class ChatViewController: MessagesViewController, InputBarAccessoryViewDelegate, MessagesDataSource, MessagesLayoutDelegate, MessagesDisplayDelegate { 9 10 11 var currentUser: User = Auth.auth().currentUser! 12 13 var user2Name: String? 14 var user2ImgUrl: String? 15 var user2UID: String? 16 17 private var docReference: DocumentReference? 18 19 var messages: [Message] = [] 20 21 override func viewDidLoad() { 22 super.viewDidLoad() 23 24 self.title = user2Name ?? "Chat" 25 26 navigationItem.largeTitleDisplayMode = .never 27 maintainPositionOnKeyboardFrameChanged = true 28 messageInputBar.inputTextView.tintColor = .lightGray 29 messageInputBar.sendButton.setTitleColor(.lightGray, for: .normal) 30 31 messageInputBar.delegate = self 32 messagesCollectionView.messagesDataSource = self 33 messagesCollectionView.messagesLayoutDelegate = self 34 messagesCollectionView.messagesDisplayDelegate = self 35 36 loadChat() 37 38 } 39 40 // MARK: - Custom messages handlers 41 42 func createNewChat() { 43 let users = [self.currentUser.uid, self.user2UID] 44 let data: [String: Any] = [ 45 "users":users 46 ] 47 48 let db = Firestore.firestore().collection("Chats") 49 db.addDocument(data: data) { (error) in 50 if let error = error { 51 print("Unable to create chat! (error)") 52 return 53 } else { 54 self.loadChat() 55 } 56 } 57 } 58 59 func loadChat() { 60 61 //Fetch all the chats which has current user in it 62 let db = Firestore.firestore().collection("Chats") 63 .whereField("users", arrayContains: Auth.auth().currentUser?.uid ?? "Not Found User 1") 64 65 66 db.getDocuments { (chatQuerySnap, error) in 67 68 if let error = error { 69 print("Error: (error)") 70 return 71 } else { 72 73 //Count the no. of documents returned 74 guard let queryCount = chatQuerySnap?.documents.count else { 75 return 76 } 77 78 if queryCount == 0 { 79 //If documents count is zero that means there is no chat available and we need to create a new instance 80 self.createNewChat() 81 } 82 else if queryCount >= 1 { 83 //Chat(s) found for currentUser 84 for doc in chatQuerySnap!.documents { 85 86 let chat = Chat(dictionary: doc.data()) 87 //Get the chat which has user2 id 88 if (chat?.users.contains(self.user2UID!))! { 89 90 self.docReference = doc.reference 91 //fetch it's thread collection 92 doc.reference.collection("thread") 93 .order(by: "created", descending: false) 94 .addSnapshotListener(includeMetadataChanges: true, listener: { (threadQuery, error) in 95 if let error = error { 96 print("Error: (error)") 97 return 98 } else { 99 self.messages.removeAll() 100 101 for message in threadQuery!.documents { 102 103 let msg = Message(dictionary: message.data()) 104 self.messages.append(msg!) 105 print("Data: (msg?.content ?? "No message found")") 106 } 107 self.messagesCollectionView.reloadData() 108 self.messagesCollectionView.scrollToBottom(animated: true) 109 } 110 }) 111 return 112 } //end of if 113 } //end of for 114 self.createNewChat() 115 } else { 116 print("Let's hope this error never prints!") 117 } 118 } 119 } 120 } 121 122 123 private func insertNewMessage(_ message: Message) { 124 125 messages.append(message) 126 messagesCollectionView.reloadData() 127 128 DispatchQueue.main.async { 129 self.messagesCollectionView.scrollToBottom(animated: true) 130 } 131 } 132 133 private func save(_ message: Message) { 134 135 let data: [String: Any] = [ 136 "content": message.content, 137 "created": message.created, 138 "id": message.id, 139 "senderID": message.senderID, 140 "senderName": message.senderName 141 ] 142 143 docReference?.collection("thread").addDocument(data: data, completion: { (error) in 144 145 if let error = error { 146 print("Error Sending message: (error)") 147 return 148 } 149 150 self.messagesCollectionView.scrollToBottom() 151 152 }) 153 } 154 155 // MARK: - InputBarAccessoryViewDelegate 156 157 func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) { 158 159 let message = Message(id: UUID().uuidString, content: text, created: Timestamp(), senderID: currentUser.uid, senderName: currentUser.displayName!) 160 161 //messages.append(message) 162 insertNewMessage(message) 163 save(message) 164 165 inputBar.inputTextView.text = "" 166 messagesCollectionView.reloadData() 167 messagesCollectionView.scrollToBottom(animated: true) 168 } 169 170 171 // MARK: - MessagesDataSource 172 func currentSender() -> SenderType { 173 174 return Sender(id: Auth.auth().currentUser!.uid, displayName: Auth.auth().currentUser?.displayName ?? "Name not found") 175 176 } 177 178 func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType { 179 180 return messages[indexPath.section] 181 182 } 183 184 func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int { 185 186 if messages.count == 0 { 187 print("No messages to display") 188 return 0 189 } else { 190 return messages.count 191 } 192 } 193 194 195 // MARK: - MessagesLayoutDelegate 196 197 func avatarSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize { 198 return .zero 199 } 200 201 // MARK: - MessagesDisplayDelegate 202 func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor { 203 return isFromCurrentSender(message: message) ? .blue: .lightGray 204 } 205 206 func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) { 207 208 if message.sender.senderId == currentUser.uid { 209 SDWebImageManager.shared.loadImage(with: currentUser.photoURL, options: .highPriority, progress: nil) { (image, data, error, cacheType, isFinished, imageUrl) in 210 avatarView.image = image 211 } 212 } else { 213 SDWebImageManager.shared.loadImage(with: URL(string: user2ImgUrl!), options: .highPriority, progress: nil) { (image, data, error, cacheType, isFinished, imageUrl) in 214 avatarView.image = image 215 } 216 } 217 } 218 219 func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle { 220 221 let corner: MessageStyle.TailCorner = isFromCurrentSender(message: message) ? .bottomRight: .bottomLeft 222 return .bubbleTail(corner, .curved) 223 224 } 225 226}
以下追記です。
Chat.swift
swift
1import UIKit 2 3struct Chat { 4 5 var users: [String] 6 7 var dictionary: [String: Any] { 8 return [ 9 "users": users 10 ] 11 } 12} 13 14extension Chat { 15 16 init?(dictionary: [String:Any]) { 17 guard let chatUsers = dictionary["users"] as? [String] else {return nil} 18 self.init(users: chatUsers) 19 } 20}
チャット画面を開こうとした際のFireatoreのフィールドは以下の画像のようになっております。
0のところに入っているのが自分のUIDになっています。
あなたの回答
tips
プレビュー