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() {
    // Do any additional setup after loading the view, typically from a nib.

override func 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. = xoffset + buttonWidth / 2 = yoffset + buttonHeight / 2

    newScore() // this works but the action above this doesn't and if I comment this line, the action above works.





source to share

2 answers

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 = newButtonX! = 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 { = buttonX
    if let buttonY = newButtonY { = 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
        // ...


Alternatively, turn off auto-layout in that storyboard / xib file. This resolves too (although it may not be acceptable for other reasons).



All Articles