delay/sleep in Swift is not working

2020-07-30 00:45发布

问题:

I have a problem with the sleep function in Swift code. I'm using import Darwin and usleep(400000). Some actions before reaching the sleep are blocked and I dont know why. Here a short example from my code:

@IBAction func Antwort4Button(_ sender: Any) {
    if (richtigeAntwort == "4"){
        Antwort4.backgroundColor = UIColor.green
        Ende.text = "Richtig!"

        NaechsteFrage()
    }
    else {
        Ende.text = "Falsch!"

        //NaechsteFrage()
    }
}

func NaechsteFrage() {
    usleep(400000)

    Antwort1.backgroundColor = UIColor.red
    Antwort2.backgroundColor = UIColor.red
    Antwort3.backgroundColor = UIColor.red
    Antwort4.backgroundColor = UIColor.red

    Ende.text = ""

    FragenSammlung()
}

This lines will be not executed:

Antwort4.backgroundColor = UIColor.green

Ende.text = "Richtig!"

Why is calling sleep blocking these actions? If I delete the import Darwin and the sleep, my code works fine. Has anyone an idea? Sorry for my bad english :P

回答1:

Others alrady answered the question, I just wanted to provide some additional information (cannot comment yet).

You said that Antwort4.backgroundColor = UIColor.green is not executed. To clarify, this is executed, but you don't see the result becuase you call sleep, which is blocking the UI. Here is what happens:

  1. set background color of Antwort4 to green
  2. sleep: block the UI which prevents the app from actually showing the green background
  3. set the background color of Antwort4 to red again

To solve the problem at hand you can use Apples Displatch API. So instead of sleept, you could use:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    self.Antwort1.backgroundColor = UIColor.red
    self.Antwort2.backgroundColor = UIColor.red
    self.Antwort3.backgroundColor = UIColor.red
    self.Antwort4.backgroundColor = UIColor.red

    self.Ende.text = ""

    self.FragenSammlung()
}


回答2:

like @jcaron said

here the code to do it:

func delay(delayTime: Double, completionHandler handler:@escaping () -> ()) {
        let newDelay = DispatchTime.now() + delayTime
        DispatchQueue.main.asyncAfter(deadline: newDelay, execute: handler)
    }

Edited: you can create a viewController extension to use in any viewControllers like this:

extension UIViewController {

    func delay(delayTime: Double, completionHandler handler:@escaping () -> ()) {
            let newDelay = DispatchTime.now() + delayTime
            DispatchQueue.main.asyncAfter(deadline: newDelay, execute: handler)
        }
}

So in your viewController you just call like this:

delay(delayTime: 2, completionHandler: {
            _ in
            // do your code here
        })


回答3:

The usleep() function will block your UI. If you don't want to have this behavior better use the Timer class.