Search code examples
iosswiftaccelerometercore-motion

How do you save data that is being produced in a handler?


The handler code (in this case, collecting accelerometer data) is being executed asynchronously when my accelerometer moves.

That means if I try to save data.x, data.y, data.z in a variable, even if the variable is declared outside of the handler, the variable will be nil if I attempt to print it anywhere.

How do I save this data to access in other parts of my code? (Or does everything have to happen in my handler, best-practices wise?)

    if motionManager.accelerometerAvailable{
                    let motionQueue = NSOperationQueue.mainQueue()
                    motionManager.startDeviceMotionUpdatesToQueue(motionQueue,
                    withHandler: gravityUpdated)
    }
 func gravityUpdated(motion: CMDeviceMotion!, error: NSError!) {
        let grav : CMAcceleration = motion.gravity;
        println(grav.x)
  }

Solution

  • The main thing to be wary of is that these events can come in more quickly than the main thread can process them. As the documentation says:

    Because the processed events might arrive at a high rate, using the main operation queue is not recommended.

    Hence, you should your own background queue to handle these events.

    Regarding how you then use this updated information on the main thread, there are two considerations:

    1. To ensure your code is thread-safe, any variables that you use both from this background thread and other threads must be synchronized.

    2. Make sure you don't just dispatch updates back to the main thread. I would generally create a dispatch source of DISPATCH_SOURCE_TYPE_DATA_OR or DISPATCH_SOURCE_TYPE_DATA_ADD, put a handler for that source on the main queue, and then your motionQueue can then then perform a dispatch_source_merge_data on this source.

      GCD will then coalesce these data changes, notifying the main thread when there were updates, but not backlogging the main thread in the process.


    By the way, you may also want to review Table 4-1 of the Event Handling Guide, which outlines common update intervals for acceleration events (measured in Hz), depending upon the intended usage:

    • 10–20: Suitable for determining a device’s current orientation vector.

    • 30–60: Suitable for games and other apps that use the accelerometer for real-time user input.

    • 70–100: Suitable for apps that need to detect high-frequency motion. For example, you might use this interval to detect the user hitting the device or shaking it very quickly.

    You might want to choose a deviceMotionUpdateInterval commensurate with your application's needs.