Strange @IBAction conflict or error? (Swift)
So I got this code for my simple iOS app. When I press the touchPressed button, the button should get a new random location on the screen, and the labelScore should update itself with the button press. A friend of mine tried this in Objective-C and it works.
The problem is I have newScore () in touchpedPressed and the button is not getting the new location. If I comment out newScore () the random location action works.
Thanks in advance.
// ViewController.swift
import UIKit
import SpriteKit
class ViewController: UIViewController {
@IBOutlet var backgroundImage: UIImageView!
@IBOutlet var scoreLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Initial score
var score:Int = 0
// Update the actual score with the one matching th number of touches
func newScore() {
score = score + 1
scoreLabel.text = "SCORE: \(score)"
}
// Get the random height for the button (with limits)
func randomButtonHeight(min: Float, max:Float) -> Float {
return min + Float(arc4random_uniform(UInt32((max-90) - min + 1)))
}
@IBAction func touchPressed(button: UIButton) {
// Find the button width and height
var buttonWidth = button.frame.width
var buttonHeight = button.frame.height
// Find the width and height of the enclosing view
var viewWidth = button.superview!.bounds.width
var viewHeight = button.superview!.bounds.height
// Compute width and height of the area to contain the button center
var xwidth = viewWidth - buttonWidth
var yheight = viewHeight - buttonHeight
// Generate a random x and y offset
var xoffset = CGFloat(arc4random_uniform(UInt32(xwidth)))
var yoffset = CGFloat(self.randomButtonHeight(100, max: Float(viewHeight)))
// Offset the button center by the random offsets.
button.center.x = xoffset + buttonWidth / 2
button.center.y = yoffset + buttonHeight / 2
newScore() // this works but the action above this doesn't and if I comment this line, the action above works.
}
}
Now that @matt has identified the problem, I have another suggestion on how to handle it:
1) Add two new vars to yours ViewController
:
var newButtonX: CGFloat?
var newButtonY: CGFloat?
2) Set them to touchPressed()
when updating the button layout.
// Offset the button center by the random offsets. newButtonX = xoffset + buttonWidth / 2 newButtonY = yoffset + buttonHeight / 2 button.center.x = newButtonX! button.center.y = newButtonY!
3) Add a button IBOutlet
for a button on ViewController
:
@IBOutlet weak var button: UIButton!
and connect it in Interface Builder.
4) Then override viewDidLayoutSubviews
like this:
override func viewDidLayoutSubviews() {
if let buttonX = newButtonX {
button.center.x = buttonX
}
if let buttonY = newButtonY {
button.center.y = buttonY
}
}
This is because of the way the paint / layout system works. You have a little temporary problem and that's it. What really happens is that the button moves, but the layout happens right after that and comes back again. One solution is to wrap everything except the call newScore
in a short delay, for example:
@IBAction func touchPressed(button: UIButton) {
delay(0) {
// Find the button width and height
var buttonWidth = button.frame.width
// ...
}
self.newScore()
}
Alternatively, turn off auto-layout in that storyboard / xib file. This resolves too (although it may not be acceptable for other reasons).