[UIKit] Firebase Chat App: Loading Conversations & Messages

Junyoung Park·2022년 9월 30일
0

UIKit

목록 보기
42/142
post-thumbnail

Swift: Firebase Chat App Part 12 - Loading Conversations & Messages (Real-time) - Xcode 11 - 2020

Firebase Chat App: Loading Conversations & Messages

구현 목표

  • 특정 대상에 대한 문자: 파이어베이스 저장 및 로드
  • 특정 대상과의 문자 뷰 UI 로직 추가

구현 태스크

  1. 대화 생성 및 추가 로직 데이터베이스 매니저 클래스 사용

핵심 코드

/// Creates a new conversation with target user email and first message sent
    func createNewConversation(with otherUserEmail: String, name: String, firstMessage: Message, completionHandler: @escaping ((Bool) -> Void)) {
        guard
            let currentEmail = UserDefaults.standard.value(forKey: "email") as? String,
            let platformString = UserDefaults.standard.value(forKey: "platform") as? String,
            let platform = Platform(rawValue: platformString) else {
            completionHandler(false)
            return
        }
        let safeEmail = DatabaseManager.safeEmail(emailAddress: currentEmail, platform: platform)
        let ref = database.child("\(safeEmail)")
        ref.observeSingleEvent(of: .value) { [weak self] snapshot in
            guard let self = self else { return }
            guard var userNode = snapshot.value as? [String : Any] else {
                completionHandler(false)
                print("User not found")
                return
            }
            let messageDate = firstMessage.sentDate
            let dateString = DateFormatter.dateFormatter.string(from: messageDate)
            var message = ""
            switch firstMessage.kind {
            case .text(let messageText):
                message = messageText
                break
            case .attributedText(_):
                break
            case .photo(_):
                break
            case .video(_):
                break
            case .location(_):
                break
            case .emoji(_):
                break
            case .audio(_):
                break
            case .contact(_):
                break
            case .linkPreview(_):
                break
            case .custom(_):
                break
            @unknown default:
                break
            }
            
            let conversationID = "conversation_" + firstMessage.messageId
            
            let newConversationData: [String:Any] = [
                "id" : conversationID,
                "name" : name,
                "other_user_email" : otherUserEmail,
                "latest_message" : [
                    "date" : dateString,
                    "message" : message,
                    "is_read" : false
                ]
            ]
            
            let recipient_newConversationData: [String:Any] = [
                "id" : conversationID,
                "name" : "Self",
                "other_user_email" : safeEmail,
                "latest_message" : [
                    "date" : dateString,
                    "message" : message,
                    "is_read" : false
                ]
            ]
            // Update recipient conversation entry
            self.database.child("\(otherUserEmail)/conversations").observeSingleEvent(of: .value) { [weak self] snapshot in
                guard let self = self else { return }
                if var conversations = snapshot.value as? [[String:Any]] {
                    // append this conversation
                    conversations.append(recipient_newConversationData)
                    self.database.child("\(otherUserEmail)/conversations").setValue(conversations)
                } else {
                    // create new conversation
                    self.database.child("\(otherUserEmail)/conversations").setValue([recipient_newConversationData])
                }
            }
            
            // Update current user conversation entry
            if var conversations = userNode["conversations"] as? [[String : Any]] {
                // Conversation array exists for current user
                // you should append
                conversations.append(newConversationData)
                userNode["conversations"] = conversations
            } else {
                // Conversation array does not exist
                // Create it
                userNode["conversations"] = [
                    newConversationData
                ]
            }
            ref.setValue(userNode) { [weak self] error, _ in
                guard let self = self else { return }
                guard error == nil else {
                    completionHandler(false)
                    return
                }
                self.finishCreatingConversation(name: name, conversationID: conversationID, firstMessage: firstMessage, completionHandler: completionHandler)
            }
        }
    }
  • 다른 사람과의 대화를 생성 및 변경하는 데이터베이스 함수
/// Gets all messages for a given conversation
    func getAllMessagesForConversation(with id: String, completionHandler: @escaping ((Result<[Message], Error>) -> Void)) {
        database.child("\(id)/messages").observe(.value) { snapshot in
            guard let value = snapshot.value as? [[String:Any]] else {
                completionHandler(.failure(DatabaseErrors.failedToFetch))
                return
            }
            
            let messages: [Message] = value.compactMap { dictionary in
                guard
                    let name = dictionary["name"] as? String,
                    let type = dictionary["type"] as? String,
                    let isRead = dictionary["is_read"] as? Bool,
                    let content = dictionary["content"] as? String,
                    let messageID = dictionary["id"] as? String,
                    let senderEmail = dictionary["sender_email"] as? String,
                    let dateString = dictionary["date"] as? String,
                    let date = DateFormatter.dateFormatter.date(from: dateString) else {
                    return nil
                }
                let sender = Sender(photoURLString: "", senderId: senderEmail, displayName: name)
                
                return Message(sender: sender,
                               messageId: messageID,
                               sentDate: date,
                               kind: .text(content))
            }
            completionHandler(.success(messages))
        }
    }
  • 파이어베이스 데이터베이스 내 저장되어 있는 대화 목록을 id를 통해 검색
  • 채팅 뷰를 구성하는 데 필요한 메시지 배열을 리턴

구현 화면

profile
JUST DO IT

1개의 댓글

comment-user-thumbnail
2024년 1월 10일

Your UIKit Firebase Chat App looks promising! It's impressive to see the progress on loading conversations and messages. If you're curious about creating a full-fledged messaging app like WhatsApp, check out this insightful article for valuable insights: https://www.cleveroad.com/blog/how-much-does-it-cost-to-create-an-app-like-whatsapp/

답글 달기