You want rapid repeat fire when your button is held down.
Your buttonDown
and buttonUp
methods need to be defined at the top level, and not inside of another function. For demonstration purposes, it is clearer to forgo wiring up @IBAction
s from the Storyboard and just set up the button in viewDidLoad
:
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
var timer: Timer?
var speedAmmo = 20
@objc func buttonDown(_ sender: UIButton) {
singleFire()
timer = Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(rapidFire), userInfo: nil, repeats: true)
}
@objc func buttonUp(_ sender: UIButton) {
timer?.invalidate()
}
func singleFire() {
print("bang!")
}
@objc func rapidFire() {
if speedAmmo > 0 {
speedAmmo -= 1
print("bang!")
} else {
print("out of speed ammo, dude!")
timer?.invalidate()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// These could be added in the Storyboard instead if you mark
// buttonDown and buttonUp with @IBAction
button.addTarget(self, action: #selector(buttonDown), for: .touchDown)
button.addTarget(self, action: #selector(buttonUp), for: [.touchUpInside, .touchUpOutside])
}
}
Also, I changed .touchUpOutside
to [.touchUpInside, .touchUpOutside]
(to catch both touch up events) and call singleFire
on the initial buttonDown
for single fire. With these changes, pressing the button fires immediately, and then fires every 0.3
seconds for as long as the button is held down.
The button can be wired up in the Storyboard instead of setting it up in viewDidLoad
. In this case, add @IBAction
to buttonDown
and buttonUp
. Then Control-click on your button in the Storyboard and drag from the circle next to Touch Down to func buttonDown
, and drag from the circles next to Touch Up Inside and Touch Up Outside to func buttonUp
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…