Swift 中的 Grand Central Dispatch 仅适用于第一个 运行

Grand Central Dispatch in Swift only works the first run

我得到了一种使用 GCD 模式的复习方法,如下所示:

    func getStepsForTheWeek() {
    let concurrentQueue : dispatch_queue_t  = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

    dispatch_async(concurrentQueue, {

        // Create an array of Days.
        var days = [Day]()

        dispatch_sync(concurrentQueue, {
            print("first")

            for day in 0...7 {

                let date = self.getDate(day)

                // Get the date the day after that day.
                let endDate = self.getDateDayAfter(date)

                // Create a Day.
                var day = Day(date: date)

                self.pedometer.queryPedometerDataFromDate(date, toDate: endDate, withHandler: {numberOfSteps, error in
                    print("fetching")

                    if error != nil {
                        print("There was an error requesting data from the pedometer: \(error)")
                    } else {
                        day.steps = numberOfSteps!.numberOfSteps as Int
                        days.append(day)
                    }
                })
            }
        })

        dispatch_sync(dispatch_get_main_queue(), {
            print("second")

            self.historyViewController.days = days
            self.historyViewController.reloadHistory()
        })
    })
}

当应用程序启动时,该方法会按预期运行。 但是当应用程序在后台并且当我返回应用程序时,我得到了这个观察者,它再次调用该方法来刷新它的内容。

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "appBecomeActive", name: UIApplicationWillEnterForegroundNotification, object: nil )

但每次我这样做时,第二个代码块都在第一个代码块之前 运行。 有帮助吗?

我认为你应该在计步器查询的完成处理程序中进行 UI 更新

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {

        self.pedometer.queryPedometerDataFromDate(date, toDate: endDate, withHandler: { numberOfSteps, error in
            if error != nil {
                print("There was an error requesting data from the pedometer: \(error)")
            } else {
                let numberOfStepsThisDay = numberOfSteps?.numberOfSteps as! Int

                day.steps = numberOfStepsThisDay
                days.append(day)
            }

            dispatch_async(dispatch_get_main_queue(), {
                self.historyViewController.days = self.days
                self.historyViewController.reloadHistory()
            })
        })
    })

你应该总是在方法的完成处理程序中更新 UI 如果它有一个,因为你不知道它是否可以是异步的(如果使用完成处理程序通常是异步的),如果除了计步器查询

之外没有其他代码,您可以删除外部 dispatch_async

我解决了。 在查询中,我检查天数数组是否已填满(例如大小为 8)。 装满后应该重新加载。我还删除了所有不必要的同步任务。现在干净多了。比我想象的要简单。

    func getStepsForTheWeek() {

    // Create an array of Days.
    var days = [Day]()

    print("first")

    // Fetch the total steps per day for 8 days (0 - 7).
    for day in 0...7 {

        // Get days date from today.
        let date = self.getDate(day)

        // Get the date the day after that day.
        let endDate = self.getDateDayAfter(date)

        // Create a Day.
        var day = Day(date: date)


        // Query the Pedometer for the total steps of that day.
        self.pedometer.queryPedometerDataFromDate(date, toDate: endDate) {
            (data, error) -> Void in
            if(error == nil){

                print("fetching")

                day.steps = data!.numberOfSteps as Int
                days.append(day)

                if(days.count == 8){
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in

                        print("finished")

                        self.historyViewController.days = days
                        self.historyViewController.reloadHistory()
                    })
                }
            }
        }
    }
}

感谢 Fonix 和 gnasher729。