2015-05-12 27 views
0

我正在編寫一個應用程序,它從HealthKit獲取步驟數據並在屏幕上顯示統計數據。我有一個委託協議功能的viewcontoller:setNeedsDisplay()和redraw()函數調用之間的延遲

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」後跟userValue從redrawRect()中的值。

現在,當我改變功能:

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中是滯後的)。

爲什麼會發生這種情況?以及如何讓它毫不遲延地工作?

回答

2

Apple Docs

查詢上的匿名後臺隊列中運行。只要查詢結果爲 完成,結果處理程序就會在相同的後臺隊列 上執行(但不一定在同一個線程上)。您通常會將這些 結果發送到主隊列以更新用戶界面。

您作爲完成處理程序異步運行的閉包,因此設置了userValue,並在後臺調用了setNeedsDisplay()。這是不好的。

應該在主線程上調用UIKit API。

一個簡單的辦法是:

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