Ios Swift Firebase多线程问题

Ios Swift Firebase多线程问题,ios,swift,multithreading,firebase,grand-central-dispatch,Ios,Swift,Multithreading,Firebase,Grand Central Dispatch,我试图在一个函数中运行几个for循环,该函数应该返回一个字符串数组 我遇到的问题是在运行下一个for循环之前获得正确的结果…然后在需要返回字符串数组以完成函数之前再次返回该结果 在第一种情况下,我有一个从Firebase获取数据的for循环。我能够使用一个调度组来获取要打印的值,但是在这之后的另一个循环中,我在上一个任务中使用调度组时遇到了问题 如果使用正确的值执行,代码都可以完美工作,但我不确定如何处理线程。非常感谢您的帮助 func findTopSpots() -> [String]

我试图在一个函数中运行几个for循环,该函数应该返回一个字符串数组

我遇到的问题是在运行下一个for循环之前获得正确的结果…然后在需要返回字符串数组以完成函数之前再次返回该结果

在第一种情况下,我有一个从Firebase获取数据的for循环。我能够使用一个调度组来获取要打印的值,但是在这之后的另一个循环中,我在上一个任务中使用调度组时遇到了问题

如果使用正确的值执行,代码都可以完美工作,但我不确定如何处理线程。非常感谢您的帮助

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

}
func findTopSpots()->[字符串]{
变量topFive=[String]()
var locationRatingDictionary=[String:Double]()
让myGroup=DispatchGroup()
let location sarray=[“怀俄明州”、“堪萨斯州”、“阿肯色州”、“佛罗里达州”、“加利福尼亚州”]
//使用天查找最常见的月份
让日历=NSCalendar.current
var monthArray=[String]()
var date=self.departureDate!
让endDate=self.returnDate!
//用于打印月份名称的格式化程序
设fmt=DateFormatter()
fmt.dateFormat=“MMMM”
//将每个月的天数添加到数组中
而日期为$1.0}
//返回5个结果
用于locationRatingTupleArray.前缀(5)中的(位置、等级){
打印(位置、等级)
topFive.append(位置)
}
打印(“前五名是\(前五名)”)
返回前五名
}

您的代码是异步的,最快的方法是完成dispatchGroup

//

func findTopSpots(完成:@escaping(arr:[string])->void){
让dispatchGroup=dispatchGroup()
变量topFive=[String]()
var locationRatingDictionary=[String:Double]()
let location sarray=[“怀俄明州”、“堪萨斯州”、“阿肯色州”、“佛罗里达州”、“加利福尼亚州”]
//使用天查找最常见的月份
让日历=NSCalendar.current
var monthArray=[String]()
var date=self.departureDate!
让endDate=self.returnDate!
//用于打印月份名称的格式化程序
设fmt=DateFormatter()
fmt.dateFormat=“MMMM”
//将每个月的天数添加到数组中
而日期为$1.0}
//返回5个结果
用于locationRatingTupleArray.前缀(5)中的(位置、等级){
打印(位置、等级)
topFive.append(位置)
}
打印(“前五名是\(前五名)”)
完成(前五名)
}
}

这里的问题是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)
    }
}
func findTopSpots(completionHandler:([String])->Void){
变量topFive=[String]()
var locationRatingDictionary=[String:Double]()
让myGroup=DispatchGroup()
let location sarray=[“怀俄明州”、“堪萨斯州”、“阿肯色州”、“佛罗里达州”、“加利福尼亚州”]
//使用天查找最常见的月份
让日历=NSCalendar.current
var monthArray=[String]()
var date=self.departureDate!
让endDate=self.returnDate!
//用于打印月份名称的格式化程序
设fmt=DateFormatter()
fmt.dateFormat=“MMMM”
//将每个月的天数添加到数组中
而日期为$1.0}
//返回5个结果
用于locationRatingTupleArray.前缀(5)中的(位置、等级){
打印(位置、等级)
topFive.append(位置)
}
打印(“前五名是\(前五名)”)
completionHandler(前五名)
}
}

hmm它在firebase文档中抛出了一个错误?FIRDocumentSnapshot GetDocumentWithSourceah my bad在两个不同的位置拥有myGroup.leave()。谢谢它看起来正在工作
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)
    }
}