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

Posted

技术标签:

【中文标题】setNeedsDisplay() 和 redraw() 函数调用之间的延迟【英文标题】:Delay between setNeedsDisplay() and call of redraw() function 【发布时间】:2015-05-12 09:42:56 【问题描述】:

我正在编写一个从 HealthKit 获取步数数据并在屏幕上显示统计数据的应用程序。我有一个带有委托协议功能的视图控制器:

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】:

Apple Docs:

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

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

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

一个简单的解决方法是:

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

【讨论】:

以上是关于setNeedsDisplay() 和 redraw() 函数调用之间的延迟的主要内容,如果未能解决你的问题,请参考以下文章

UIScrollView 子视图和 setNeedsDisplay

使用 drawRect、setNeedsDisplay 和 layoutSubViews

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

自定义 UITableViewCell 不会在 setNeedsDisplay 上重绘

iOS开发:setNeedsLayOut和setNeedsDisplay区别

setNeedsDisplay 打破 UIView 的自动布局动画