class AppDelegate: UIResponder, UIApplicationDelegate { func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) { updateValues(completionHandler) } func updateValues(fetchCompletionHandler: (UIBackgroundFetchResult) -> Void) { // Use a dispatch group to monitor the asynchronous calls let updateGroup = dispatch_group_create() var currentWeather: Weather? var currentMotion: Motion? var currentMotionMPS: Double? // meter per second var currentPulse: Pulse? var currentPulseBPM: Double? // beats per minute // If there is a location tracked, check for the current motion and speed if let location = locationManager.currentLocation { // Motion // Calculate the current motion and speed based on the current location if let previousLocation = locationManager.previousLocation { currentMotionMPS = motionManager.speedForLocation(location, previousLocation: previousLocation) currentMotion = motionManager.motionForSpeed(currentMotionMPS!) } // Weather // Query the current weather at the current location dispatch_group_enter(updateGroup) let weatherManager = WeatherManager() weatherManager.weatherDataForLocation(location) { (data, error) -> Void in if let weather = data { currentWeather = weather } else { print("WeatherManager Error: \(error)") } dispatch_group_leave(updateGroup) } } else { print("LocationManager Error: Current location not found") } // Pulse // Get the current pulse from HealthKit dispatch_group_enter(updateGroup) vc.healthManager.queryPulseWithCompletion({ (pulse, pulseBPM, error) -> Void in if error == nil && pulse != nil { print("HealthManager Success") vc.currentPulse = pulse! vc.currentPulseBMP = pulseBPM! } else { print("HealthManager Error: \(error)") } dispatch_group_leave(updateGroup) }) // When the asynchronous calls finish, start the upload dispatch_group_notify(updateGroup, dispatch_get_main_queue(), { () -> Void in fireBaseManager.updateValues(currentMotion, motionMPS: currentMotionMPS, pulse: currentPulse, pulseBPM: currentPulseBPM, weather: currentWeather) { _ in // In this case, we assume that we always have new data fetchCompletionHandler(.NewData) } }) } } class HealthManager { var store: HKHealthStore? lazy var queryObjectTypes:Set? = { if let types:Set = [HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)!] { return types } else { return nil } }() init() { if (HKHealthStore.isHealthDataAvailable()) { store = HKHealthStore() } else { print(NSError(domain: "healthManagerError", code: 0, userInfo: nil)) } } // To access the data of the HealthStore, you have to request for authorization. This automatically presents the system's permission form func requestAuthorizationWithCompletion(completion: ((NSError?) -> Void)) { store?.requestAuthorizationToShareTypes(queryObjectTypes, readTypes: queryObjectTypes, completion: { (success, error) -> Void in if success { completion(nil) } else { completion(NSError(domain: "healthManagerError", code: 0, userInfo: nil)) } }) } func queryPulseWithCompletion(completion: ((Pulse?, Double?, NSError?) -> Void)) { if HKHealthStore.isHealthDataAvailable() { let sampleType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)! let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false) // Create a sample query with a completion handler let query = HKSampleQuery(sampleType: sampleType, predicate: nil, limit: 0, sortDescriptors: [sortDescriptor], resultsHandler: { (query, samples, error) -> Void in // If there are samples, get the first sample and return it's pulse information if let samples = samples, let firstSample = samples.first as? HKQuantitySample { let quantity = firstSample.quantity let pulseUnit = HKUnit(fromString: "count/min") if quantity.isCompatibleWithUnit(pulseUnit) { let pulseBPM = quantity.doubleValueForUnit(pulseUnit) let pulse = self.pulseForBPM(pulseBPM) // returns Pulse.Low, .Medium or .High completion(pulse, pulseBPM, nil) } else { completion(nil, nil, NSError(domain: "healthManagerError", code: 1, userInfo: nil)) } } else { completion(nil, nil, NSError(domain: "healthManagerError", code: 1, userInfo: nil)) } }) // Execute the query store?.executeQuery(query) } } }