Проблема многопоточности Swift Firebase - PullRequest
0 голосов
/ 04 июня 2018

Я пытаюсь запустить пару циклов for внутри функции, которая должна возвращать массив строк.

У меня возникают проблемы с получением правильных результатов ДО того, как будет запущен следующий цикл for ... и затем снова с возвращением этих результатов ДО того, как мне нужно будет вернуть массив строк для завершения функции.

В первом случае у меня есть цикл for, который получает данные из Firebase.Мне удалось использовать группу диспетчеризации, чтобы получить значение для печати - но затем с другим циклом после этого - у меня были проблемы с использованием группы диспетчеризации в предыдущей задаче.

Код все работает отличноесли выполняется с правильными значениями, но я не уверен, как это сделать в отношении потоков.Буду очень признателен за любую помощь.

func findTopSpots() -> [String] {

    var topFive = [String]()
    var locationRatingDictionary = [String:Double]()
    let myGroup = DispatchGroup()
    let locationsArray = ["wyoming", "kansas", "arkansas", "florida", "california"]

    // Use the days to find the most common month
    let calendar = NSCalendar.current
    var monthArray = [String]()
    var date = self.departureDate!
    let endDate = self.returnDate!

    // Formatter for printing the month name
    let fmt = DateFormatter()
    fmt.dateFormat = "MMMM"

    // Add each days month to an array
    while date <= endDate {
        date = calendar.date(byAdding: .day, value: 1, to: date)!
        monthArray.append(fmt.string(from: date))
    }

    // Return the primary month from function
    let primaryMonth = findMostCommonMonthInArray(array: monthArray).lowercased()

    // Create a dictionary of location:rating for the primary month
    for doc in locationsArray {
        self.db.collection("locations").document(doc).collection("historic").document(primaryMonth).getDocument { (document, err) in
            if let document = document, document.exists {
                let rating = document["rating"] as? Double
                locationRatingDictionary[doc] = rating
            } else {
                print("Document does not exist")
            }
        }
    }

    //---- THE CODE BELOW WILL NOT PRINT WITH ANY VALUES ----//
    print(locationRatingDictionary)

    // Sort the tuple array by rating
    let locationRatingTupleArray = locationRatingDictionary.sorted{ $0.value > $1.value }

    // Return 5 results
    for (location,rating) in locationRatingTupleArray.prefix(5) {
        print(location,rating)
        topFive.append(location)
    }

    print("top five are \(topFive)")
    return topFive

}

Ответы [ 2 ]

0 голосов
/ 04 июня 2018

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

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

func findTopSpots(completionHandler:([String])->Void) {

    var topFive = [String]()
    var locationRatingDictionary = [String:Double]()
    let myGroup = DispatchGroup()
    let locationsArray = ["wyoming", "kansas", "arkansas", "florida", "california"]

    // Use the days to find the most common month
    let calendar = NSCalendar.current
    var monthArray = [String]()
    var date = self.departureDate!
    let endDate = self.returnDate!

    // Formatter for printing the month name
    let fmt = DateFormatter()
    fmt.dateFormat = "MMMM"

    // Add each days month to an array
    while date <= endDate {
        date = calendar.date(byAdding: .day, value: 1, to: date)!
        monthArray.append(fmt.string(from: date))
    }

    // Return the primary month from function
    let primaryMonth = findMostCommonMonthInArray(array: monthArray).lowercased()

    // Create a dictionary of location:rating for the primary month
    for doc in locationsArray {
        myGroup.enter()     self.db.collection("locations").document(doc).collection("historic").document(primaryMonth).getDocument { (document, err) in
            if let document = document, document.exists {
                let rating = document["rating"] as? Double
                locationRatingDictionary[doc] = rating
            } else {
                print("Document does not exist")
            }
            myGroup.leave()
        }
    }

    myGroup.notify(queue:.main) {
        //---- THE CODE BELOW WILL NOT PRINT WITH ANY VALUES ----//
        print(locationRatingDictionary)

        // Sort the tuple array by rating
        let locationRatingTupleArray = locationRatingDictionary.sorted{ $0.value > $1.value }

        // Return 5 results
        for (location,rating) in locationRatingTupleArray.prefix(5) {
            print(location,rating)
            topFive.append(location)
        }

        print("top five are \(topFive)")
        completionHandler(topFive)
    }
}
0 голосов
/ 04 июня 2018

Ваш код асинхронный самый быстрый способ - это dispatchGroup с завершением

//

func findTopSpots(completion:@escaping(_ arr:[string])->void){

    let dispatchGroup = DispatchGroup()
    var topFive = [String]()
    var locationRatingDictionary = [String:Double]()
    let locationsArray = ["wyoming", "kansas", "arkansas", "florida", "california"]

    // Use the days to find the most common month
    let calendar = NSCalendar.current
    var monthArray = [String]()
    var date = self.departureDate!
    let endDate = self.returnDate!

    // Formatter for printing the month name
    let fmt = DateFormatter()
    fmt.dateFormat = "MMMM"

    // Add each days month to an array
    while date <= endDate {
        date = calendar.date(byAdding: .day, value: 1, to: date)!
        monthArray.append(fmt.string(from: date))
    }

    // Return the primary month from function
    let primaryMonth = findMostCommonMonthInArray(array: monthArray).lowercased()

    // Create a dictionary of location:rating for the primary month
    for doc in locationsArray {
       dispatchGroup.enter()
   self.db.collection("locations").document(doc).collection("historic").document(primaryMonth).getDocument { (document, err) in
            if let document = document, document.exists {
                let rating = document["rating"] as? Double
                locationRatingDictionary[doc] = rating
            } else {
                print("Document does not exist")
            }
            dispatchGroup.leave()
        }
    } 

   dispatchGroup.notify(queue: .main) {

         //---- THE CODE BELOW WILL NOT PRINT WITH ANY VALUES ----//
    print(locationRatingDictionary)

    // Sort the tuple array by rating
    let locationRatingTupleArray = locationRatingDictionary.sorted{ $0.value > $1.value }

    // Return 5 results
    for (location,rating) in locationRatingTupleArray.prefix(5) {
        print(location,rating)
        topFive.append(location)
    }

    print("top five are \(topFive)")

    completion(topFive)

  }
}
...