2016-04-11 10 views
13

Sto realizzando una rapida app iOS che si integra con il conteggio dei passi di un utente, come riportato dall'app Salute. Posso facilmente trovare conteggio dei passi per l'utente nelle ultime ore, usando questo come il mio predicato:HealthKit Swift ottiene i passi di oggi

let anHourBeforeNow: NSDate = NSDate().dateByAddingTimeInterval(-60 * 60) 
let predicate = HKQuery.predicateForSamplesWithStartDate(anHourBeforeNow, endDate: NSDate(), options: .None) 

E ho il resto verso il basso, in modo da poter accedere correttamente conteggio dei passi per l'utente per l'ultima ora. Ma come posso accedere ai dati dei passi dell'utente dall'inizio della giornata, come mostra l'app Salute nella sezione dei passaggi?

che sto cercando di fare qualcosa di simile:

let date = NSDate() 
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! 
let newDate = cal.startOfDayForDate(date) 
let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) 

ma questo codice non viene adattata per il fuso orario (in modo che mi dà l'inizio della giornata in UTC, non l'inizio della giornata in cui l'utente è) e sto anche ricevendo conteggi di step molto gonfiati (per ragioni sconosciute).

Così come posso ottenere conteggio dei passi per l'utente per il giorno corrente, con lo stesso numero di passaggi come riportato in salute, come nella foto qui:enter image description here

+0

questo può aiutare a vedere la risposta rapida http://stackoverflow.com/questions/29582462/get-total-step-count-for-every-date -in-healthkit –

+0

Dovresti includere il codice per la tua query e come calcoli il conteggio dei passi in modo che possiamo aiutarti con questo problema. Puoi anche seguire le mie risposte a http://stackoverflow.com/questions/36560367/health-handles-multiple-step-sources-differently-than-healthkit-swift per ricevere una guida se risulta che stai commettendo lo stesso errore. – Allan

+0

Cosa restituisce NSTimeZone.localTimeZone() nella tua app? – Allan

risposta

15

Ecco il modo giusto usando HKStatisticsCollectionQuery per gentile concessione di direzione dal codice di cui sopra.

Questo è scritto in Swift 3 quindi potrebbe essere necessario convertire parte del codice in 2.3 o 2 se non in 3 ancora.

Swift 3

func retrieveStepCount(completion: (stepRetrieved: Double) -> Void) { 

     // Define the Step Quantity Type 
     let stepsCount = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount) 

     // Get the start of the day   
     let date = Date() 
     let cal = Calendar(identifier: Calendar.Identifier.gregorian) 
     let newDate = cal.startOfDay(for: date) 

     // Set the Predicates & Interval 
     let predicate = HKQuery.predicateForSamples(withStart: newDate, end: Date(), options: .strictStartDate) 
     var interval = DateComponents() 
     interval.day = 1 

     // Perform the Query 
     let query = HKStatisticsCollectionQuery(quantityType: stepsCount!, quantitySamplePredicate: predicate, options: [.cumulativeSum], anchorDate: newDate as Date, intervalComponents:interval) 

     query.initialResultsHandler = { query, results, error in 

      if error != nil { 

       // Something went Wrong 
       return 
      } 

      if let myResults = results{ 
       myResults.enumerateStatistics(from: self.yesterday, to: self.today) { 
        statistics, stop in 

        if let quantity = statistics.sumQuantity() { 

         let steps = quantity.doubleValue(for: HKUnit.count()) 

         print("Steps = \(steps)") 
         completion(stepRetrieved: steps) 

        } 
       } 
      } 


     } 

     storage.execute(query) 
    } 

Objective-C

HKQuantityType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; 

NSDate *today = [NSDate date]; 
NSDate *startOfDay = [[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian] startOfDayForDate:today]; 

NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startOfDay endDate:today options:HKQueryOptionStrictStartDate]; 
NSDateComponents *interval = [[NSDateComponents alloc] init]; 
interval.day = 1; 

HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:type quantitySamplePredicate:predicate options:HKStatisticsOptionCumulativeSum anchorDate:startOfDay intervalComponents:interval]; 

query.initialResultsHandler = ^(HKStatisticsCollectionQuery * _Nonnull query, HKStatisticsCollection * _Nullable result, NSError * _Nullable error) { 
    if (error != nil) { 
    // TODO 
    } else { 
    [result enumerateStatisticsFromDate:startOfDay toDate:today withBlock:^(HKStatistics * _Nonnull result, BOOL * _Nonnull stop) { 
     HKQuantity *quantity = [result sumQuantity]; 
     double steps = [quantity doubleValueForUnit:[HKUnit countUnit]]; 
     NSLog(@"Steps : %f", steps); 
    }]; 
    } 
}; 

[self.storage executeQuery:query]; 
+0

@Gugulethu puoi per favore guidare come posso troncare manualmente i passaggi aggiunti da questo? – Byte

+0

@Byte Sto solo cercando di capire le tue domande: vuoi troncare i passaggi aggiunti manualmente da un'altra fonte oltre a HealthKit? – Gugulethu

+0

NO, voglio ottenere tutti i passaggi rilevati da iphone e aggiunti automaticamente da altri tracker. Ma non voglio quei passaggi che gli utenti hanno aggiunto manualmente nell'app di salute. – Byte

4

La query che si stava utilizzando prende tutto l'utente del registrati passi da Healthkit, non facendo il filtro intelligente di passaggi duplicati l'app di salute. Invece, si desidera ottenere i dati di aggregazione aggregati prodotti dall'applicazione Salute dopo aver combinato passaggi da origini diverse per ottenere un conteggio accurato.

Per fare questo, è possibile utilizzare questo codice:

func recentSteps2(completion: (Double, NSError?) ->()) 
{ // this function gives you all of the steps the user has taken since the beginning of the current day. 

    checkAuthorization() // checkAuthorization just makes sure user is allowing us to access their health data. 
    let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) // The type of data we are requesting 


    let date = NSDate() 
    let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! 
    let newDate = cal.startOfDayForDate(date) 
    let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) // Our search predicate which will fetch all steps taken today 

    // The actual HealthKit Query which will fetch all of the steps and add them up for us. 
    let query = HKSampleQuery(sampleType: type!, predicate: predicate, limit: 0, sortDescriptors: nil) { query, results, error in 
     var steps: Double = 0 

     if results?.count > 0 
     { 
      for result in results as! [HKQuantitySample] 
      { 
       steps += result.quantity.doubleValueForUnit(HKUnit.countUnit()) 
      } 
     } 

     completion(steps, error) 
    } 

    storage.executeQuery(query) 
} 
+2

Ci dispiace, ma questo non è corretto. HKSampleQuery restituisce ogni record di passo (non rimuove i duplicati) ed è un modo inefficiente per calcolare la somma di campioni corrispondenti a un predicato. Dovresti utilizzare HKStatisticsQuery. – Allan

1

Utilizzando le risposte di cui sopra e da Apple qui: https://developer.apple.com/reference/healthkit/hkstatisticsquery ho ottenuto il seguente a lavorare in rapida 2.3 su Xcode 8.0 .

class func getStepCountHealth(startDate: NSDate, endDate: NSDate, completion:(Double?, NSError?)->()) { 

      let healthKitStore:HKHealthStore = HKHealthStore() 

      // Define the sample type 
      let sampleType = HKQuantityType.quantityTypeForIdentifier(
      HKQuantityTypeIdentifierStepCount) 

      // Set the predicate 
      let predicate = HKQuery.predicateForSamplesWithStartDate(startDate, 
                   endDate: endDate, options: .None) 
      // build the query 
      let sampleQuery = HKStatisticsQuery(quantityType: sampleType!, 
             quantitySamplePredicate: predicate, 
             options: .CumulativeSum) { query, results, error in 

             if results != nil { 
              let quantity = results?.sumQuantity() 
              let unit = HKUnit.countUnit() 
              let totalSteps = quantity?.doubleValueForUnit(unit) 
              completion(totalSteps, error) 
//           print("totalSteps for \(endDate) are \(totalSteps!)") 
             } else { 
              completion(nil, error) 
//           print("results are nil") 
              return 
             } 
            } 
      // execute the Query 
      healthKitStore.executeQuery(sampleQuery) 
     } 
8

HKStatisticsCollectionQuery è più adatto da utilizzare quando si desidera recuperare i dati in un intervallo di tempo. Utilizzare HKStatisticsQuery per ottenere solo i passaggi per un giorno specifico.

Swift 3 & 4:

let healthStore = HKHealthStore() 

    func getTodaysSteps(completion: @escaping (Double) -> Void) { 
     let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount)! 

     let now = Date() 
     let startOfDay = Calendar.current.startOfDay(for: now) 
     let predicate = HKQuery.predicateForSamples(withStart: startOfDay, end: now, options: .strictStartDate) 

     let query = HKStatisticsQuery(quantityType: stepsQuantityType, quantitySamplePredicate: predicate, options: .cumulativeSum) { (_, result, error) in 
      guard let result = result, let sum = result.sumQuantity() else { 
       log.error("Failed to fetch steps = \(error?.localizedDescription ?? "N/A")") 
       completion(0.0) 
       return 
      } 

      DispatchQueue.main.async { 
       completion(sum.doubleValue(for: HKUnit.count())) 
      } 
     } 

     healthStore.execute(query) 
    } 
+0

Questa soluzione è più semplice e più efficiente di quella accettata. – chengsam

Problemi correlati