Sagar Snehi
Sagar Snehi

Reputation: 398

Execute a function after completing all background process in swift

I am using GCD in swift like this :

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {

    //all background task

    dispatch_async(dispatch_get_main_queue()) {  
        self.second()
    }
}

In this code second function is getting called before completing all background task that's why I am not able to take some data which I am using in second function. I want to second method after completing all background task. Can anyone tell me how to achieve this task?

***************In background I am taking healthkit data like******

let healthKitTypesToRead = 
Set(
        arrayLiteral: HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierDateOfBirth)!,
        HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierBiologicalSex)!,
        HKObjectType.workoutType()
        )

let newCompletion: ((Bool, NSError?) -> Void) = {
        (success, error) -> Void in

        if !success {
            print("You didn't allow HealthKit to access these write data types.\nThe error was:\n \(error!.description).")

            return
        }
        else
      {
       let stepCount = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)

                    // Our search predicate which will fetch data from now until a day ago
                    // (Note, 1.day comes from an extension
                    // You'll want to change that to your own NSDate

                    //let date = NSDate()
                    //let predicate = HKQuery.predicateForSamplesWithStartDate(date, endDate: NSDate(), options: .None)

                    // The actual HealthKit Query which will fetch all of the steps and sub them up for us.
                    let stepCountQuery = HKSampleQuery(sampleType: stepCount!, predicate:.None, 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())
                            }
                            testClass.HK_stepCount = String(steps)
                        }

                        //completion(steps, error)
                    }

                    self.healthKitStore.executeQuery(stepCountQuery)
             //EDIT.....
          let tHeartRate = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)
            let tHeartRateQuery = HKSampleQuery(sampleType: tHeartRate!, predicate:.None, limit: 0, sortDescriptors: nil) { query, results, error in
                if results?.count > 0
                {
                    var string:String = ""
                    for result in results as! [HKQuantitySample]
                    {
                        let HeartRate = result.quantity
                        string = "\(HeartRate)"
                        print(string)
                    }
                    testClass.HK_HeartRate = string
                      finalCompletion(Success: true)

                }

            }
                 self.healthKitStore.executeQuery(tHeartRateQuery)
      }

    }


healthKitStore.requestAuthorizationToShareTypes(healthKitTypesToWrite, readTypes: healthKitTypesToRead, completion: newCompletion)

I am not able to take value of step count, It get executed after calling second(method) called, plz suggest me what to do?

Upvotes: 1

Views: 1635

Answers (1)

Akshansh Thakur
Akshansh Thakur

Reputation: 5331

You can create a separate function to execute your task on other thread

func someFunction(finalCompletion: (Success: Bool)->()) {
let healthKitTypesToRead = 
Set(
        arrayLiteral: HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierDateOfBirth)!,
        HKObjectType.characteristicTypeForIdentifier(HKCharacteristicTypeIdentifierBiologicalSex)!,
        HKObjectType.workoutType()
        )

let newCompletion: ((Bool, NSError?) -> Void) = {
        (success, error) -> Void in

        if !success {
            print("You didn't allow HealthKit to access these write data types.\nThe error was:\n \(error!.description).")

            return
        }
        else
      {
       let stepCount = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)

                    // Our search predicate which will fetch data from now until a day ago
                    // (Note, 1.day comes from an extension
                    // You'll want to change that to your own NSDate

                    //let date = NSDate()
                    //let predicate = HKQuery.predicateForSamplesWithStartDate(date, endDate: NSDate(), options: .None)

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

                        if results?.count > 0
                        {

                           // Edit--  
                            for result in results as! [HKQuantitySample]
                            {
                                steps += result.quantity.doubleValueForUnit(HKUnit.countUnit())
                             //   heartBeat += ....
                            }
                            testClass.HK_stepCount = String(steps)
                            finalCompletion(Success: true)

                        }

                        //completion(steps, error)
                    }

                    self.healthKitStore.executeQuery(stepCountQuery)
      }

    }


healthKitStore.requestAuthorizationToShareTypes(healthKitTypesToWrite, readTypes: healthKitTypesToRead, completion: newCompletion)
}

Another function?

I will edit this answer in some time to tell you about a better technique to deal with async request. In general you should have a separate singleton class for such background tasks. (RESTful API service class.. but for now you can use the below method)

func getHeartBeatInfo(finalCompletionHeart: (Success: Bool)->()) {

 let tHeartRate = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeartRate)
        let tHeartRateQuery = HKSampleQuery(sampleType: tHeartRate!, predicate:.None, limit: 0, sortDescriptors: nil) { query, results, error in
            if results?.count > 0
            {
                var string:String = ""
                for result in results as! [HKQuantitySample]
                {
                    let HeartRate = result.quantity

                    string = "\(HeartRate)"
                    print(string)
                }
                testClass.HK_HeartRate = string
                  finalCompletionHeart(Success: true)

            }

        }
             self.healthKitStore.executeQuery(tHeartRateQuery)
   }

And then you can call this method like so:

override func viewDidLoad() {

      someFunction( { (finalCompletion) in

         if finalCompletion == true {

            getHeartBeatInfo( { finalCompletionHeart in

                if finalCompletionHeart == true {

                      self.second()
                }

            })
         }
      })
}

Upvotes: 1

Related Questions