Rhythmus
Rhythmus

Reputation: 201

CMMotionActivityManager queryActivityStarting data not available outside closure

I have this code to get historical motion activity from using CoreMotionActivity.

func buildActivityArray() -> Array<Any> {

  let now = Date()
  let then = Date().addingTimeInterval(-3600)

  var motionManager: CMMotionActivityManager!
  motionManager = CMMotionActivityManager()

  var activityList: [Any] = []

  motionManager.queryActivityStarting(from: then, to: now, to: .main) { motionActivities, error in

      if let error = error {
          print("error: \(error.localizedDescription)")
          return
      }

      motionActivities?.forEach { activity in

          if activity.confidence == .medium || activity.confidence == .high {

              if activity.stationary {
                  activityList.append("stationary")
                  activityList.append(Int(activity.timestamp))
              } else if activity.walking {
                  activityList.append("walking")
                  activityList.append(Int(activity.timestamp))
              } else if activity.running {
                  activityList.append("running")
                  activityList.append(Int(activity.timestamp))
              }
          }
      }

      print("** activityList = ", activityList)
  }

  print("* activityList = ", activityList)

  return(activityList)

}

The first print statement returns the array with data, but the 2nd print statement is always empty. It looks like the 2nd print statement gets executed before the motionManager.queryActivityStarting closure completes executing, and therefore returns empty array.

How do I wait for the closure to finish before executing the 2nd print statement?

Thank you for your help

Upvotes: 0

Views: 688

Answers (1)

Siyu
Siyu

Reputation: 12089

Yes you're right, the second print gets executed first. This is because the method queryActivityStarting is async.

According to Apple's doc

This method runs asynchronously, returning immediately and delivering the results to the specified handler block. A delay of up to several minutes in reported activities is expected.

The handler block which is your "closure" is very similar to callback function in js.

So, you will need to write your business logic in this handler block. Of course, to keep your code clean, it's advisable to call another method instead of writing all in this block. Moreover, you can add observer on activityList if you wish to get notified (then invoke other functions) when its value gets changed.

Upvotes: 1

Related Questions