Add a delay to a for loop in swift

2020-03-23 18:22发布

I have a coding 'issue'.

I have a label, which text I want to change dynamically every 2 seconds. I've done the following:

// WELCOME STRING ARRAY
let welcomeContainer:[String] = ["Welcome","Benvenuti","Bienvenue","Willkommen","üdvözlet","Dobrodošli","добро пожаловать","Witajcie","Bienvenido","Ласкаво просимо","Vitajte","欢迎你来"]

and then, rather than using a timerwithinterval (which seemed to be too much for this simple task), I tried with the delay method in my function inside for loop:

func welcomeLabelChange() {
for i in 0..<welcomeContainer.count {
    welcomeLabel.text = welcomeContainer[i]
    delay(delay: 2.0, closure: {})
}

Unfortunately it's entirely skipping the delay... the for loop is executed instantly and just the last text in the array is displayed. What am I doing wrong?

I found this OBJ-C answer, but it's suggesting an (old) NSTimer implementation.

6条回答
戒情不戒烟
2楼-- · 2020-03-23 18:32

You can add sleep function

for i in 0..<welcomeContainer.count {
    welcomeLabel.text = welcomeContainer[i]
    sleep(2) // or sleep(UInt32(0.5)) if you need Double
}
查看更多
小情绪 Triste *
3楼-- · 2020-03-23 18:39

If you want to keep it all inline you can do this:

var loop: ((Int) -> Void)!
loop = { [weak self] count in
  guard count > 0 else { return }
  //Do your stuff
  DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    loop(count - 1)
  }
}
loop(10) //However many loops you want
查看更多
Fickle 薄情
4楼-- · 2020-03-23 18:40

define those variables

var i = 0
let timer : Timer?

Place this timer in your view did load or wherever you want to start the label change

   timer =  Timer.scheduledTimer(timeInterval: 2.0, target: self, selector:#selector(YourViewController.changeText), userInfo: nil, repeats: true)

and implement this method:

func changeText(){
    if i>=welcomeContainer.count {
        i = 0
    }

    welcomeLabel.text = welcomeContainer[i]
    i += 1
}

when you want to stop it or change the view controller dont forget to call

timer.invalidate()
查看更多
迷人小祖宗
5楼-- · 2020-03-23 18:44

You can also use this function to delay something

//MARK: Delay func 

func delay(_ delay:Double, closure:@escaping ()->()) {
    DispatchQueue.main.asyncAfter(
        deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}

and usage is :

        delay(2)  //Here you put time you want to delay
{
            //your delayed code
        }

Hope it will help you.

查看更多
唯我独甜
6楼-- · 2020-03-23 18:45

Marked answer doesn't delay loop iterations and you still get just the last value in the label.text.

You can solve it like this:

func showWelcome(_ iteration: Int = 0) {
    let i = iteration>=self.welcomeContainer.count ? 0 : iteration
    let message = self.welcomeContainer[i]
    self.delay(2){
        self.welcomeLabel.text = message
        return self.showWelcome(i + 1)
    }
}

Usage:

    showWelcome()
查看更多
男人必须洒脱
7楼-- · 2020-03-23 18:50

With Timer, you should be careful to call invalidate of the Timer in viewDidDisappear or else you may not release the view controller.

Alternatively, you can use a GCD dispatch timer, in which you completely eliminate the strong reference cycle by using [weak self] pattern:

@IBOutlet weak var welcomeLabel: UILabel!

var timer: DispatchSourceTimer!

override func viewDidLoad() {
    super.viewDidLoad()

    let welcomeStrings = ["Welcome", "Benvenuti", "Bienvenue", "Willkommen", "üdvözlet", "Dobrodošli", "добро пожаловать", "Witajcie", "Bienvenido", "Ласкаво просимо", "Vitajte", "欢迎你来"]
    var index = welcomeStrings.startIndex
    timer = DispatchSource.makeTimerSource(queue: .main)
    timer.scheduleRepeating(deadline: .now(), interval: .seconds(2))
    timer.setEventHandler { [weak self] in
        self?.welcomeLabel.text = welcomeStrings[index]
        index = index.advanced(by: 1)
        if index == welcomeStrings.endIndex {
            index = welcomeStrings.startIndex // if you really want to stop the timer and not have this repeat, call self?.timer.cancel()
        }
    }
    timer.resume()
}
查看更多
登录 后发表回答