Firebase getDocument запускается построчно? - PullRequest
1 голос
/ 02 мая 2020

Я быстрый новичок в Firebase, я столкнулся с проблемой, которая меня сильно смущает. Мы все знаем, что следующий код

var a = [Int]()
for i in 0..2{
    a.append(i)
    print(a)
print(a)

должен дать мне вывод

[0]
[0,1]
[0,1,2]
[0,1,2]

И это верно как результат. Однако, когда я работаю над getDocument () и пишу аналогичный код logi c, вывод получается странным! Код следующий:

override func viewDidLoad() {
    super.viewDidLoad()
    let docSecond = getThirtyData()
    getDataContent(thirtyData: docSecond)
}
func getThirtyData()->Array<Int>{
    var querySecond = [Int]()
    var docSecond = [Int]()
    let postDoc = db.collection("announcement")
    postDoc.getDocuments { (querySnapshot, err) in
        if let err = err{
            print("Error getting documents: \(err)")
        }else{
            for document in querySnapshot!.documents{
                //print(document.data()["postTimeSecondInt"] as! Int)
                querySecond.append(document.data()["postTimeSecondInt"] as! Int)
            }
            for _ in 1...querySecond.count{
                let max = querySecond.max()!
                docSecond.append(max)
                let index = querySecond.firstIndex(of: max)
                querySecond.remove(at: index!)
            }
            print(docSecond)
            print("123")
        }
    }
    print(docSecond)
    print("456")
    return docSecond
}

func getDataContent(thirtyData: [Int]){
    print(thirtyData)
    print("789")
}

Я думал, что результатом может быть тот же лог c, в котором сначала будет напечатано «123», затем «456», затем «789». Тем не менее, результат выглядит следующим образом.

[]
456
[]
789
[1588428987, 1588428980, 1588427392]
123

Похоже, что он запускает строку кода ниже одновременно с for для l oop. Кто-нибудь может объяснить, почему это происходит?

1 Ответ

1 голос
/ 02 мая 2020

Это работает как задумано / задокументировано, но если вы никогда не использовали асинхронный API, это действительно может сбить с толку. Причина того, что код выполняется не по порядку, заключается в том, что postDoc.getDocuments() должен считывать данные с сервера, что может занять некоторое время. Вместо того, чтобы блокировать ваш код (и, таким образом, удерживать пользователя от использования вашего приложения), ваш основной код может продолжаться. И затем, когда данные доступны с сервера, ваш обработчик завершения вызывается с этими данными.

Проще всего это увидеть, добавив несколько операторов регистрации:

print("Before starting to load data")
let postDoc = db.collection("announcement")
postDoc.getDocuments { (querySnapshot, err) in
    print("Got data");
}
print("After starting to load data")

Когда вы запустите это минимальный код, он печатает:

Перед началом загрузки данных

После начала загрузки данных

Получил данные

Это работа по назначению, но на самом деле очень запутанная, если вы еще никогда не работали с асинхронными или управляемыми событиями API. К сожалению, большинство современных облачных / веб-API являются асинхронными, поэтому лучше всего привыкнуть к этому шаблону. Надеюсь, мои объяснения, приведенные выше, немного помогут в этом.

Две важные вещи, которые нужно запомнить:

  • Ваш print(docSecond) не печатает нужные данные, потому что docSecond.append(max) hasn ' пока не выполняется.
  • Любой код, которому нужны данные из базы данных, должен находиться внутри обработчика завершения, который вызывается с этими данными (или вызывается оттуда).

You не может вернуть данные, которые загружены асинхронно. Типичным обходным решением является создание пользовательского обработчика завершения, очень похожего на обработчик завершения, который Firestore getDocuments() принимает postDoc.getDocuments { (querySnapshot, err) in, но затем с вашим собственным типом.

Что-то вроде:

func getThirtyData(_ completion: (Array<Int>) -> ()) {
    var querySecond = [Int]()
    var docSecond = [Int]()
    let postDoc = db.collection("announcement")
    postDoc.getDocuments { (querySnapshot, err) in
        if let err = err{
            print("Error getting documents: \(err)")
        }else{
            for document in querySnapshot!.documents{
                querySecond.append(document.data()["postTimeSecondInt"] as! Int)
            }
            for _ in 1...querySecond.count{
                let max = querySecond.max()!
                docSecond.append(max)
                let index = querySecond.firstIndex(of: max)
                querySecond.remove(at: index!)
            }
            completion(docSecond)
        }
    }
}

А затем назовите это как:

getThirtyData { docSecond in
   getDataContent(thirtyData: docSecond)
}

См. Также:

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