在 swift 中为 for 循环添加延迟
Add a delay to a for loop in swift
我有一个编码'issue'。
我有一个标签,我想每 2 秒动态更改其中的文本。
我做了以下事情:
// WELCOME STRING ARRAY
let welcomeContainer:[String] = ["Welcome","Benvenuti","Bienvenue","Willkommen","üdvözlet","Dobrodošli","добро пожаловать","Witajcie","Bienvenido","Ласкаво просимо","Vitajte","欢迎你来"]
然后,我没有使用 timerwithinterval
(对于这个简单的任务来说似乎太多了),而是尝试在 for
循环中的函数中使用 delay
方法:
func welcomeLabelChange() {
for i in 0..<welcomeContainer.count {
welcomeLabel.text = welcomeContainer[i]
delay(delay: 2.0, closure: {})
}
不幸的是,它完全跳过了延迟... for 循环立即执行,只显示数组中的最后一个文本。
我做错了什么?
我找到了这个 OBJ-C answer,但它建议使用(旧的)NSTimer
实现。
定义那些变量
var i = 0
let timer : Timer?
将此计时器放置在您已加载的视图中或您想要开始标签更改的任何位置
timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector:#selector(YourViewController.changeText), userInfo: nil, repeats: true)
并实现这个方法:
func changeText(){
if i>=welcomeContainer.count {
i = 0
}
welcomeLabel.text = welcomeContainer[i]
i += 1
}
当你想停止它或改变视图控制器时不要忘记调用
timer.invalidate()
使用Timer
时,请注意在viewDidDisappear
中调用Timer
的invalidate
,否则可能无法释放view controller。
或者,您可以使用 GCD 调度计时器,在其中使用 [weak self]
模式完全消除强引用循环:
@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()
}
你也可以使用这个功能来延迟一些事情
//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)
}
用法是:
delay(2) //Here you put time you want to delay
{
//your delayed code
}
希望对您有所帮助。
标记的答案不会延迟循环迭代,您仍然只得到 label.text 中的最后一个值。
你可以这样解决:
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)
}
}
用法:
showWelcome()
可以添加休眠功能
for i in 0..<welcomeContainer.count {
welcomeLabel.text = welcomeContainer[i]
sleep(2) // or sleep(UInt32(0.5)) if you need Double
}
如果你想保持内联,你可以这样做:
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
我有一个编码'issue'。
我有一个标签,我想每 2 秒动态更改其中的文本。 我做了以下事情:
// WELCOME STRING ARRAY
let welcomeContainer:[String] = ["Welcome","Benvenuti","Bienvenue","Willkommen","üdvözlet","Dobrodošli","добро пожаловать","Witajcie","Bienvenido","Ласкаво просимо","Vitajte","欢迎你来"]
然后,我没有使用 timerwithinterval
(对于这个简单的任务来说似乎太多了),而是尝试在 for
循环中的函数中使用 delay
方法:
func welcomeLabelChange() {
for i in 0..<welcomeContainer.count {
welcomeLabel.text = welcomeContainer[i]
delay(delay: 2.0, closure: {})
}
不幸的是,它完全跳过了延迟... for 循环立即执行,只显示数组中的最后一个文本。 我做错了什么?
我找到了这个 OBJ-C answer,但它建议使用(旧的)NSTimer
实现。
定义那些变量
var i = 0
let timer : Timer?
将此计时器放置在您已加载的视图中或您想要开始标签更改的任何位置
timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector:#selector(YourViewController.changeText), userInfo: nil, repeats: true)
并实现这个方法:
func changeText(){
if i>=welcomeContainer.count {
i = 0
}
welcomeLabel.text = welcomeContainer[i]
i += 1
}
当你想停止它或改变视图控制器时不要忘记调用
timer.invalidate()
使用Timer
时,请注意在viewDidDisappear
中调用Timer
的invalidate
,否则可能无法释放view controller。
或者,您可以使用 GCD 调度计时器,在其中使用 [weak self]
模式完全消除强引用循环:
@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()
}
你也可以使用这个功能来延迟一些事情
//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)
}
用法是:
delay(2) //Here you put time you want to delay
{
//your delayed code
}
希望对您有所帮助。
标记的答案不会延迟循环迭代,您仍然只得到 label.text 中的最后一个值。
你可以这样解决:
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)
}
}
用法:
showWelcome()
可以添加休眠功能
for i in 0..<welcomeContainer.count {
welcomeLabel.text = welcomeContainer[i]
sleep(2) // or sleep(UInt32(0.5)) if you need Double
}
如果你想保持内联,你可以这样做:
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