Ожидание, пока определенная задача полностью не завершится, чтобы выполнить другую задачу - PullRequest
0 голосов
/ 03 мая 2019

Я пытаюсь получить некоторые сообщения шифрования из базы данных Firebase Realtime, расшифровать их и отобразить в CollectionView. Процесс дешифрования прошел успешно, но я столкнулся с проблемой многопоточности: неправильный порядок извлечения-извлечения сообщений, добавляемых в массив Messages, поэтому они не отображаются в CollectionView с правильным порядком, в порядке отображения сообщений. в CollectionView меняется во время каждого запуска. Я думал, что эта проблема возникает из-за того, что время, необходимое для завершения процесса дешифрования каждого зашифрованного сообщения, отличается, некоторым зашифрованным сообщениям требуется больше времени для расшифровки, а некоторые зашифрованные сообщения заканчивают дешифрование раньше других, поэтому порядок их добавления в массив сообщений больше не правильно. Рабочий процесс, который я ожидаю, что:

  1. Выполнение запроса на выборку для узла сообщений в базе данных Firebase
  2. С каждым полученным сообщением:
    3,1. Расшифровать
    3,2. Добавьте его в массив сообщений
    3,3. Перезагрузите CollectionView для обновления пользовательского интерфейса

Но я не знаю, как использовать GCD для достижения этого правильно, отображаемые сообщения не в правильном порядке из-за проблемы параллелизма. Но я нашел решение, что если я попытаюсь поместить команду sleep(1) в мой код, код будет работать правильно, но он будет слишком медленным из-за спящей команды. Я пробовал много способов, но это кажется неправильным, за исключением использования команды sleep(1). Пожалуйста, помогите мне сделать это правильно, большое спасибо! Вот мой код:

func observeMessage(){ 
        self.eThree = VirgilHelper.sharedVirgilHelper.eThreeToUse!

        // Get current user's UID
        guard let uid = FIRAuth.auth()?.currentUser?.uid , let toId = self.user?.id else {
            return;
        }

        let userMessagesRef = FIRDatabase.database().reference().child("user-messages").child(uid).child(toId);
        userMessagesRef.observe(.childAdded, with: { (snapshot) in

            let messageId = snapshot.key;
            let messagesRef = FIRDatabase.database().reference().child("messages").child(messageId);
            // Observe the entire value of that node
            messagesRef.observeSingleEvent(of: .value, with: { (snapshot) in

                if let dictionary = snapshot.value as? [String:AnyObject] {

                //sleep(1) // The working sleep command, but it's too slow

                let message = Message(dictionary: dictionary)
                    if let fromUID = message.fromId, let toUID = message.toId, let cipherText = message.text {

                        self.eThree!.lookupPublicKeys(of: [fromUID], completion: { (lookupResult, error) in
                            if error != nil {
                                print("Error when looking up the Public Key of UID \(fromUID), \(String(describing: error))")
                            }
                            if let lookupResult = lookupResult {
                                message.text = try! self.eThree!.decrypt(text: cipherText, from: lookupResult[fromUID]!)
                                print("text: \(message.text)")

                                // The concurency prolem happens at here
                                self.messages.append(message);

                                // Go back to main thread to update UI
                                DispatchQueue.main.async {
                                    // The concurency prolem happens at here, UI doesn't display with correct order of fetched-decrypted messages
                                    self.collectionView?.reloadData()

                                    let indexPath = IndexPath(item: self.messages.count-1, section: 0)
                                    self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true);
                                }
                            }

                        })
                    }
                }

            }, withCancel: nil)
        }, withCancel: nil)

    }

1 Ответ

0 голосов
/ 03 мая 2019

В Swift, чтобы дождаться выполнения другой задачи, прежде чем продолжить выполнение другой задачи, вы можете использовать DispatchQueue.group ().

let group = DispatchGroup()

group.enter()
DispatchQueue.main.async {
    print("1")
    group.leave()
}

group.enter()
DispatchQueue.main.async {
    print("2")
    group.leave()
}

group.enter()
DispatchQueue.main.async {
    print("3")
    group.leave()
}

group.notify(queue: .main) {
    print("Done")
}

Таким образом, как вы ее используете:

  1. Инициализация группы
  2. Введите группу с помощью: group.enter (), прежде чем запускать задачу
  3. Put: group.leave (), после каждой задачи
  4. Передайте закрытие group.notify.Он будет выполнен, когда групповое задание пусто.

ПРИМЕЧАНИЕ: Число .enter () должно совпадать с .leave ()

...