前提・実現したいこと
FireStoreにデータを保存したい。
送信ボタンが押された時に、Firestoreに => 送信者のuid/受信者のuid/autoId(自動生成される)/data の様な階層構造で保存したいのですが、
エラーが発生しているのですが、エラーの内容が理解できていません。。。
エラ発生のタイミングはFireStoreにデータを保存するタイミングです。
ドキュメントの参照には偶数のセグメントが必要とあるのですが、そのセグメントはどこで変更するのかわかっていません。
発生している問題・エラーメッセージ
Thread 1: Exception: "FIRESTORE INTERNAL ASSERTION FAILED: Invalid document reference. Document references must have an even number of segments, but messages has 1" FIRESTOREの内部アサーションに失敗しました:無効なドキュメント参照。 ドキュメント参照には偶数のセグメントが必要ですが、メッセージには1つあります
###breakPointでのエラーの箇所
/* * Copyright 2019 Google * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Firestore/core/src/util/exception_apple.h" #import <Foundation/Foundation.h> #include <exception> #include "Firestore/core/src/util/hard_assert.h" #include "Firestore/core/src/util/string_apple.h" NS_ASSUME_NONNULL_BEGIN namespace firebase { namespace firestore { namespace util { namespace { NSString* ExceptionName(ExceptionType exception) { switch (exception) { case ExceptionType::AssertionFailure: return @"FIRESTORE INTERNAL ASSERTION FAILED"; case ExceptionType::IllegalState: return @"FIRIllegalStateException"; case ExceptionType::InvalidArgument: return @"FIRInvalidArgumentException"; } UNREACHABLE(); } NSException* MakeException(ExceptionType type, const std::string& message) { return [[NSException alloc] initWithName:ExceptionName(type) reason:MakeNSString(message) userInfo:nil]; } } // namespace ABSL_ATTRIBUTE_NORETURN void ObjcThrowHandler(ExceptionType type, const char* file, const char* func, int line, const std::string& message) { if (type == ExceptionType::AssertionFailure) { [[NSAssertionHandler currentHandler] handleFailureInFunction:MakeNSString(func) file:MakeNSString(file) lineNumber:line description:@"%@: %s", ExceptionName(type), message.c_str()]; std::terminate(); } else { @throw MakeException(type, message); // NOLINT //⇦ここでエラーが出る。 } } } // namespace util } // namespace firestore } // namespace firebase NS_ASSUME_NONNULL_END
該当のソースコード
###ChatViewController
extension ChatController: CustomInputViewDelegate { func inputView(_ inputView: CustomInputAccessoryView, wantsToSend message: String) { Service.uploadMessage(message, to: user) { (error) in if let error = error { print("DEBUG: failed to upload message with error (error.localizedDescription)") return } inputView.cleraMessageText() } } }
customInputView内のsendButtonが有り、押されるとdelgateでChatViewControllerにmessageが入ってきます。
Service.swift
struct Service { static let shared = Service() static func fetchUsers(completion: @escaping([User], Error?) -> Void) { var users = [User]() Firestore.firestore().collection("users").getDocuments { (snapShot, error) in if let error = error { completion(users,error) return } guard let snapShot = snapShot else{ completion(users,error) return } snapShot.documents.forEach { (document) in let dictionary = document.data() let user = User(dictionary: dictionary as [String: AnyObject]) users.append(user) } completion(users, nil) } } //⇩ static func uploadMessage(_ message: String, to user: User, completion: ((Error?) -> Void)?) { guard let currentUid = Auth.auth().currentUser?.uid else {return} let data = ["message": message, "fromId": currentUid, "toId": user.uid, "timestamp": Timestamp(date: Date())] as [String: Any] COLLECTION_MESSAGES.document(currentUid).collection(user.uid).addDocument(data: data) { _ in COLLECTION_MESSAGES.document(user.uid).collection(currentUid).addDocument(data: data, completion: completion) } } }
###customInputAccesorryView
import UIKit protocol CustomInputViewDelegate: class{ func inputView(_ inputView: CustomInputAccessoryView, wantsToSend message: String) } class CustomInputAccessoryView: UIView { //MARK: - Properties weak var delegate: CustomInputViewDelegate? internal let messageInputTextView: UITextView = { let tv = UITextView() tv.font = UIFont.systemFont(ofSize: 16) tv.isScrollEnabled = false tv.backgroundColor = .clear tv.textColor = .black return tv }() private let sendButton: UIButton = { let button = UIButton(type: .system) button.setTitle("Send", for: .normal) button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14) button.setTitleColor(.systemPurple, for: .normal) button.addTarget(self, action: #selector(handleSendMessage), for: .touchUpInside) return button }() private let placeHolderLabel: UILabel = { let label = UILabel() label.text = "Enter Message" label.font = UIFont.systemFont(ofSize: 16) label.textColor = .lightGray return label }() //MARK: - View LifeCycle override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .white autoresizingMask = [.flexibleHeight] layer.shadowOpacity = 0.25 layer.shadowRadius = 10 layer.shadowOffset = .init(width: 0, height: -8) layer.shadowColor = UIColor.lightGray.cgColor addSubview(sendButton) sendButton.anchor(top: topAnchor, right: rightAnchor, paddingTop: 4, paddingRight: 8) sendButton.setDimensions(height: 50, width: 50) addSubview(messageInputTextView) messageInputTextView.anchor(top: topAnchor, left: leftAnchor, bottom: safeAreaLayoutGuide.bottomAnchor, right: sendButton.leftAnchor, paddingTop: 12, paddingLeft: 4, paddingBottom: -4 ,paddingRight: 8) addSubview(placeHolderLabel) placeHolderLabel.anchor(left: messageInputTextView.leftAnchor, paddingLeft: 4) placeHolderLabel.centerY(inView: messageInputTextView) NotificationCenter.default.addObserver(self, selector: #selector(handleTextInputChange), name: UITextView.textDidChangeNotification, object: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override var intrinsicContentSize: CGSize { return .zero } //MARK: - Selector's @objc func handleSendMessage() { guard let text = messageInputTextView.text else {return} delegate?.inputView(self, wantsToSend: text) } @objc func handleTextInputChange() { placeHolderLabel.isHidden = !self.messageInputTextView.text.isEmpty sendButton.isEnabled = !self.messageInputTextView.text.isEmpty } //MARK: - Helpers func cleraMessageText() { messageInputTextView.text = nil placeHolderLabel.isHidden = false sendButton.isEnabled = false } }
xcode 11
swift 5
回答1件
あなたの回答
tips
プレビュー