setNeedsDisplay()和redraw()函数调用之间的延迟

时间:2015-05-12 09:42:57

标签: ios swift uiview drawrect

我正在编写一个从HealthKit获取步骤数据的应用程序,并在屏幕上显示统计信息。我有一个带有委托协议功能的viewcontoller:

func userValueForHistogramView(sender: HistogramView) -> CGFloat? {
        return userValue
    }

其中userValue为:

var userValue : CGFloat = 1000 {
    didSet{
        println("DidSet")
        histogramView.setNeedsDisplay()
    }
}

HistogramView上的drawRect函数如下所示:

override func drawRect(rect: CGRect) {
        var value = dataSource?.userValueForHistogramView(self)
        println("\(value)")
    }

我通过以下函数启动userValue的更新:

func startRefreshByGettingUserValue()

当功能简单:

func startRefreshByGettingUserValue(){
        userValue = 1500;
}

我收到一条即时日志消息" DidSet"后跟redrawRect()的userValue值。

现在,当我将功能更改为:

func startRefreshByGettingUserValue(){
        let calendar = NSCalendar.currentCalendar()
        let today = NSDate()

        let components = calendar.components(.CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay, fromDate: today)

        let startDate = calendar.dateFromComponents(components)

        let endDate = calendar.dateByAddingUnit(.CalendarUnitDay,
            value: 1, toDate: startDate!, options: NSCalendarOptions(0))

        let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, endDate: endDate, options: .StrictStartDate)

        let sampleQuery = HKStatisticsQuery(quantityType: HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount), quantitySamplePredicate: predicate, options: .CumulativeSum)
            { (sampleQuery, results, error ) -> Void in

                if let quantity = results?.sumQuantity(){
                    self.userValue = CGFloat(quantity.doubleValueForUnit(HKUnit.countUnit()) )

                }
        }
        HKStore.executeQuery(sampleQuery)
}

我得到了瞬间" DidSet"日志中的消息,但实际值在10秒后出现(即drawRect滞后)。

为什么会这样?以及如何让它毫不拖延地工作?

1 个答案:

答案 0 :(得分:2)

Apple Docs

  

查询在匿名后台队列上运行。一旦查询是   完成后,结果处理程序在同一个后台队列上执行   (但不一定在同一个线程上)。你通常派遣这些   结果到主队列更新用户界面。

作为完成处理程序以异步方式传入的闭包,因此设置了userValue并在后台调用了setNeedsDisplay()。那不好。

应该在主线程上调用UIKit API。

一个简单的解决方法是:

var userValue : CGFloat = 1000 {
    didSet{
        println("DidSet")
        dispatch_async(dispatch_get_main_queue()) {
            histogramView.setNeedsDisplay()
        }
    }
}