我想创建一个启动倒计时的按钮,但在倒计时期间,按钮'图像'与传递的秒数相关的变化(例如3 - 新按钮,2 - 新按钮,1 - 新按钮)。我相信到目前为止我所获得的是实现这一目标的最有效方式。
然而,在运行时,没有图像更改,也没有在循环的下一次迭代之前等待。代码在Swift 3.0中,如下所示(省略所有初始化等):
var countDown = ["buttonThree", "buttonTwo", "buttonOne", "buttonRelease", "buttonMain"]
//The Button in its initial state
@IBAction func playBtn(_ sender: UIButton) {
var imageCounter:Int = 0
//Begin Loop
while imageCounter != 3 {
let playBtn = UIButton(type: .custom)
playBtn.setImage(UIImage(named: countDown[imageCounter]), for: .normal)
imageCounter = imageCounter + 1
_ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (timer) in }
print("Working")
}
//Delay on third iteration
if imageCounter == 3 {
//Execute recording
_ = DispatchTime.now() + 5
}
//Return to normal state after 5 second delay
let playBtn = UIButton(type: .custom)
playBtn.setImage(UIImage(named: countDown[4]), for: .normal)
}
答案 0 :(得分:0)
这段代码有很多问题。我会尝试解释,但你真的应该回到你的书,并实际学习基础知识。你的语法正确,但你所写的内容没有任何意义。
此外,由于您提到您认为这是最有效的方式:现在不要担心性能或效率。要学习的最重要的事情是编写正确的程序,当你得到它时你可能会担心效率。即便如此,也不要太担心,只有在实际测量性能后才应进行优化。
var countDown = ["buttonThree", "buttonTwo", "buttonOne", "buttonRelease", "buttonMain"]
除非您打算更改此阵列,否则您应在此处使用let
。
//The Button in its initial state
@IBAction func playBtn(_ sender: UIButton) {
你的功能名称并不好。 Swift风格不使用Btn
之类的缩写,您可以拼出Button
。但即使playButton
在这里也不是一个好名字,它没有说明这种方法有什么用处。更好的名称是playPushed
或者只是play
。
var imageCounter:Int = 0
//Begin Loop
while imageCounter != 3 {
虽然这种循环风格确实有效,并且它没有任何错误,但惯用的快速方式将使用for in
循环。也是"开始循环"评论不是必需的,很明显,循环从此处开始 - 您可以从while
关键字中看到它。
let playBtn = UIButton(type: .custom)
playBtn.setImage(UIImage(named: countDown[imageCounter]), for: .normal)
当然,您的按钮不会更改图像。在这里,您可以创建一个新按钮,设置它的图像并丢弃该按钮。除非将其添加到视图层次结构中,否则永远不会显示此按钮。但这在这里也没有意义 - 你想要改变当前按钮,而不是添加新按钮。
此处已有正确的按钮,这是sender
参数。
imageCounter = imageCounter + 1
_ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (timer) in }
定时器不能像这样工作 - 它们在经过一段时间后执行传递的闭包,它们不会在给定时间内暂停当前线程。你的闭包({ (timer) in }
部分)什么也没做。
print("Working")
}
//Delay on third iteration
if imageCounter == 3 {
//Execute recording
_ = DispatchTime.now() + 5
这也不符合您的想法。这不是延迟,它只计算未来5秒的时间点,然后通过_ =
部分忽略。
}
//Return to normal state after 5 second delay
let playBtn = UIButton(type: .custom)
playBtn.setImage(UIImage(named: countDown[4]), for: .normal)
同样,您不是在更新UI中的按钮,而是创建一个新的按钮,然后将其丢弃。
}
有很多方法可以写出来。保持代码形状的最简单方法是在循环中启动多个计时器,每次更改都有不同的延迟。
@IBAction
func playPushed(_ sender: UIButton) {
sender.isEnabled = false
let lastCountDownButton = 3
for (offset, imageName) in countdown[0...lastCountDownButton].enumerated() {
_ = Timer.scheduledTimer(withTimeInterval: TimeInterval(offset), repeats: false) { _ in
sender.setImage(UIImage(named: imageName), for: .normal)
if offset == lastCountDownButton {
// Execute recording
_ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { _ in
sender.setImage(UIImage(named: countdown[4]), for: .normal)
sender.isEnabled = true
}
}
}
}
}
我做了一个小改动,同时禁用按钮,直到整个过程完成。否则,用户可能会多次启动整个序列,从而导致意外行为。
我还使用while
循环代替for in
循环来生成子阵列countdown[0...lastCountDownButton]
。除了实际项目之外,enumerated()
函数返回一个包含偏移量(从0开始计算)的新序列。
在一个真实的应用程序中,我会写这个不同的。我将整个逻辑封装在一个由单个计时器驱动的状态机中。