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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Firebase

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

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

iOS

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

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

0回答

1658閲覧

MessageKitでのFirestoreとのやり取りについて

yotubarail

総合スコア23

Firebase

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

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

iOS

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

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

0クリップ

投稿2020/04/20 02:53

編集2020/04/20 07:33

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になっています。
イメージ説明

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

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

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

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

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

TsukubaDepot

2020/04/20 05:46

if (chat?.users.contains(self.user2UID!))! 上の行はオプショナルチェインに対して強制アンラップしているので、chatが万が一nilだったときには実行時エラーになってしまいますし、オプショナルチェインの意味がありません(もっとも、テキストの書き方がそうなっているので、質問者さんの責任でもありませんが)。 コード全てが追えないのでヒント程度になりますが、 let chat = Chat(dictionary: doc.data()) で Chat のイニシャライザがnilを返していたりしないでしょうか。 また、doc.data() はもっともらしいデータを返していますでしょうか。 この辺りを逐一チェックすると解決策が見つかるかもしれませんし、調べた上で結果を教えていただければ、もしかしたら解決するかもしれません。
yotubarail

2020/04/20 07:35

アドバイスをいただきありがとうございます。 ご指摘いただいた部分をチェックをしてみます。 少しでもスムーズに進められればと質問の方に追記を行いましたので、お時間ある時に目を通していただけますと幸いです。
TsukubaDepot

2020/04/21 22:06

コードを追っていて気になったのですが、user2UID には何か適切な値は入れていますでしょうか。 行頭でString?として宣言してありますが、サンプルコードのままだと何も入力されないままここに到達しますが、!で強制アンラップしているのでサンプル通りだと当然落ちてしまいます。
yotubarail

2020/04/22 01:30

確かにそうですね ご指摘ありがとうございます Firebaseで他のユーザーのUIDを取得する方法を調べて、試してみます
TsukubaDepot

2020/04/22 02:29

私自身、Firebsdeに詳しくなくて今回のページを参考に試してみているのですが、 https://medium.com/@ibjects/simple-text-chat-app-using-firebase-in-swift-5-b9fa91730b6c 上記のページの途中に、ログイン情報の取得、ならびにユーザIDなどの取得は別途行なう必要がある、とありますが、そちらの情報は得られていますでしょうか。 もし、ユーザ情報などを取得できていれば、それらのデータを var user2Name: String? var user2ImgUrl: String? var user2UID: String? の各変数に代入してあげれば良さそうな感じがします。
TsukubaDepot

2020/04/22 02:37

ちなみに、本文のこの辺りですね。 Information from GoogleSignIn: When you authenticate a user using GoogleSignIn, you get access to some of their information from which we’ll use the following: User Display name (Which we’ll use as senderName) User UID (The unique id of user which we’ll use to differentiate different users i.e. senderID) User Photo (We’ll use it to show as avatar of user sending message)
yotubarail

2020/04/22 02:52

理由はわからないのですがViewを開いた後たまにエラーが出るまでに多少時間がかかる時があり、試しにメッセージを送信したところ自分が設定したImage等は表示されていました。メッセージを送信したらcollectionにthreadという欄が追加されるかと思っていたのですが、特に変化はないようでした。 このことから自分のアカウント情報は取得できていると考えているので、課題としては別のユーザーのUID等の情報をどのように持ってくるかというところかと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問