I am trying to change the text of a UILabel each time the device gets shaken. I needed some workaround to capture the shake more frequently than the UIEventSubtype shake.
The motionMethod
gets called, though the text of my UILabel stays the same for several seconds before it finally updates.
So here is my code:
let delegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var player:Player!
var motionManager: CMMotionManager?
let accThreshold = 1.0
var referenceTime = NSDate()
let timeThreshold = 0.2
override func viewDidLoad() {
super.viewDidLoad()
player = delegate.chancesPlayer
let queue = NSOperationQueue()
motionManager = delegate.motionManager
motionManager?.startDeviceMotionUpdatesToQueue(queue, withHandler: {
(motion: CMDeviceMotion!, error:NSError!) in
self.motionMethod(motion)
})
}
and the motionMethod
:
func motionMethod(deviceMotion: CMDeviceMotion){
var acceleration = deviceMotion.userAcceleration
if fabs(acceleration.x) > accThreshold || fabs(acceleration.y) > accThreshold || fabs(acceleration.z) > accThreshold{
if -referenceTime.timeIntervalSinceNow > timeThreshold{
referenceTime = NSDate()
player.grow()
println("Player ist now at size: \(player.growth)") //this gets called frequently...
growthTF.text = "Player ist now at size: \(player.growth)" //...that doesn't
}
}
}
So why is there a delay in the update of the text?
You're updating the label on a thread other than the main (UI) thread, which is undefined behavior. You should either use GCD to dispatch back to the main thread for the UI updates inside the closure, like this:
func motionMethod(deviceMotion: CMDeviceMotion){
var acceleration = deviceMotion.userAcceleration
if fabs(acceleration.x) > accThreshold || fabs(acceleration.y) > accThreshold || fabs(acceleration.z) > accThreshold{
if -referenceTime.timeIntervalSinceNow > timeThreshold{
referenceTime = NSDate()
player.grow()
dispatch_async(dispatch_get_main_queue()) {
growthTF.text = "Player ist now at size: \(player.growth)" //...that doesn't
}
}
}
}
Or, you could specify that the updates should happen on the main queue.
motionManager?.startDeviceMotionUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler: {