简体   繁体   中英

UILabel doesn't update the text called inside a core motion closure

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: {

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM