Синхронное чтение из Firebase - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть значение, которое мне нужно прочитать из Firebase, а затем записать его вместе с несколькими другими значениями в Firebase в транзакции из двух объектов.

Я создаю ЧАТ и поэтому, когда сообщение отправляется, я создаю чат-комнату для обоих контактов, каждый из которых имеет свой собственный. Мой код:

private func CreateChatRoom(creatorID: String, creatorName: String ,contactID: String, contactName: String)
    {

        var creatorImageString: String = ""
        var contactImageString: String = ""
        ReadContactImage(contactID: contactID)
        {
            success in

            if success
            {
                contactImageString = self.tempContactImg
            }
        }
        ReadContactImage(contactID: creatorID)
        {
            success in

            if success
            {
                creatorImageString = self.tempContactImg
            }
        }

        let infoForCreator = [Constants.Chat.ChatRoomsLite.CONTACT_NAME: contactName,
                              Constants.Chat.ChatRoomsLite.CONTACT_ID: contactID,
                              Constants.Chat.ChatRoomsLite.NUM_OF_UNREAD_MSGS : 0,
                              Constants.Chat.ChatRoomsLite.CONTACT_IMG_URL: contactImageString] as [String : Any]


        let infoForContact = [Constants.Chat.ChatRoomsLite.CONTACT_NAME: creatorName,
                              Constants.Chat.ChatRoomsLite.CONTACT_ID: creatorID,
                              Constants.Chat.ChatRoomsLite.NUM_OF_UNREAD_MSGS : 0,
                              Constants.Chat.ChatRoomsLite.CONTACT_IMG_URL: creatorImageString] as [String : Any]

        let childUpdates = ["\(creatorID)/\(contactID)/": infoForCreator,
                            "\(contactID)/\(creatorID)/": infoForContact
                           ]

        Constants.refs.databaseChatsLite.updateChildValues(childUpdates)
    }

    private func ReadContactImage(contactID: String, completion: @escaping (Bool) -> ())
    {
        Constants.refs.databaseUsers.child(contactID).child(Constants.Account.AccountFields.USER_IMAGE_STR).observeSingleEvent(of: .value, with: {(snapshot) in

            self.tempContactImg = (snapshot.value as? String)!
            completion(true)
        })
    }

    var tempContactImg : String = "";

Я прочитал здесь на SO, что функция "ReadContactImage" должна работать синхронно, но это не так. Так что я остался с пустыми изображениями контактов.

Я думал о том, чтобы просто прочитать оба изображения в одной и той же функции, но CreateChatRoom также должен быть синхронным, поэтому в принципе у меня осталась одна и та же проблема.

Кто-нибудь знает, как правильно с этим справиться?

Может быть, есть более простой способ сделать это?

Edit:

Если запись в базу данных асинхронна, я получаю исключение:

func AddChatToCollections(chatAsDictionary: NSDictionary!)
    {
        if chatAsDictionary == nil
        {
            return
        }
        let contactName = chatAsDictionary[Constants.Chat.ChatRoomsLite.CONTACT_NAME] as! String
        let contactImg = chatAsDictionary[Constants.Chat.ChatRoomsLite.CONTACT_IMG_URL] as! String
        //let lastMsg = chatAsDictionary["lastMessage"] as! String
        let newMsgs = chatAsDictionary[Constants.Chat.ChatRoomsLite.NUM_OF_UNREAD_MSGS] as! Int
        let contactID = chatAsDictionary[Constants.Chat.ChatRoomsLite.CONTACT_ID] as! String

        let chatToAdd = PrivateChatLiteObject(chattingWith: contactName, ContactID: contactID, unreadMessages: newMsgs, LastMSG: "", ContactImageStr: contactImg)


        chatsDictionary[contactID] = chatToAdd
        chatsIndex.append(contactID)
    }

При попытке использовать информацию в словаре, которая взята из Firebase. Эта функция вызывается отсюда:

private func populateActiveChats()
    {
        let loggedOnUserID = Auth.auth().currentUser?.uid
        let ref = Constants.refs.databaseChatsLite.child(loggedOnUserID!)

        // Retrieve the products and listen for changes
        ref.observe(.value, with:
                { (snapshot) in

                    for child in snapshot.children.allObjects as! [DataSnapshot]
                    {

                        if (self.chatsDictionary.keys.contains(child.key) == false)
                        {
                            let chatValueDictionary = child.value as? NSDictionary
                            self.AddChatToCollections(chatAsDictionary: chatValueDictionary)
                            self.DispatchQueueFunc()
                        }


                    }
            })
    }

Который вызывается с viewDidLoad(), когда я открываю страницу чатов.

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

Поскольку chatAsDictionary [CONTACT_NAME] не существует, потому что, когда chatAsDictionary получает свои данные из Firebase, они еще не записываются туда из асинхронной функции

1 Ответ

0 голосов
/ 01 ноября 2018

Оба метода вы вызываете загружать данные из Firebase асинхронно. Вы не можете создать infoForCreator (и другие), пока оба вызова ReadContactImage не завершатся.

Простой способ сделать это - вложить вызовы:

var creatorImageString: String = ""
var contactImageString: String = ""
ReadContactImage(contactID: contactID)
{
    success in

    if success
    {
        contactImageString = self.tempContactImg
        ReadContactImage(contactID: creatorID)
        {
            success in

            if success
            {
                creatorImageString = self.tempContactImg

                let infoForCreator = [Constants.Chat.ChatRoomsLite.CONTACT_NAME: contactName,
                      Constants.Chat.ChatRoomsLite.CONTACT_ID: contactID,
                      Constants.Chat.ChatRoomsLite.NUM_OF_UNREAD_MSGS : 0,
                      Constants.Chat.ChatRoomsLite.CONTACT_IMG_URL: contactImageString] as [String : Any]


let infoForContact = [Constants.Chat.ChatRoomsLite.CONTACT_NAME: creatorName,
                      Constants.Chat.ChatRoomsLite.CONTACT_ID: creatorID,
                      Constants.Chat.ChatRoomsLite.NUM_OF_UNREAD_MSGS : 0,
                      Constants.Chat.ChatRoomsLite.CONTACT_IMG_URL: creatorImageString] as [String : Any]

let childUpdates = ["\(creatorID)/\(contactID)/": infoForCreator,
                    "\(contactID)/\(creatorID)/": infoForContact
                   ]

                   Constants.refs.databaseChatsLite.updateChildValues(childUpdates)
            }
        }
    }
}

Альтернатива, вы можете сохранить счетчик:

var creatorImageString: String = ""
var contactImageString: String = ""
var completedCount = 0;
ReadContactImage(contactID: contactID)
{
    success in

    if success
    {
        contactImageString = self.tempContactImg
        completedCount++
        if completedCount == 2
        {
            createDatabaseNode(contactImageString, creatorImageString)
        }
    }
}
ReadContactImage(contactID: creatorID)
{
    success in

    if success
    {
        creatorImageString = self.tempContactImg
        completedCount++
        if completedCount == 2
        {
            createDatabaseNode(contactImageString, creatorImageString)
        }
    }
}

И createDatabaseNode - это функция, которая содержит ваш код для заполнения структур данных и вызывает updateChildValues.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...