0

Im trying to generate an array of 10 buttons using a for-in-loop and then animating them using a for-in-loop that is inside of a CADisplayLink but the problem is that only one button is being created and animated. Please Help! Thanks in advance!

var buttons: [UIButton] = Array(count: 10, repeatedValue: UIButton.buttonWithType(.System) as UIButton)

override func viewDidLoad() {
    super.viewDidLoad()

    var displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:")
    displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

    for index in 0...10 - 1{

        var xLocation:CGFloat = CGFloat(arc4random_uniform(300) + 30)

        buttons[index].frame = CGRectMake(xLocation, 10, 100, 100)
        buttons[index].setTitle("Test Button \(index)", forState: UIControlState.Normal)
        buttons[index].addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)

        self.view.addSubview(buttons[index])

    }



}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

}

func handleDisplayLink(displayLink: CADisplayLink) {

    for index in 0...10 - 1{

        var buttonFrame = buttons[index].frame
        buttonFrame.origin.y += 1
        buttons[index].frame = buttonFrame
        if buttons[index].frame.origin.y >= 500 {
            displayLink.invalidate()
        }
    }
}


func buttonAction(sender: UIButton) {
    sender.alpha = 0
}

}

Garret Kaye
  • 2,412
  • 4
  • 21
  • 45

1 Answers1

1

The constructor Array(count:, repeatedValue:) does not execute the UIButton constructor multiple times. It receives a value and then repeats it, you just happen to instantiate the pointer in-line.

What you have done is functionally the same as:

var aButton:UIButton = UIButton.buttonWithType(.System) as UIButton
var buttons: [UIButton] = Array(count: 10, repeatedValue:aButton)

Splitting the arguments up in this way makes the operation of the Array constructor much clearer.


What you probably wanted to do was something more like:

var buttons:[UIButton] = Array()
for index in 1...10 {
  buttons.append(UIButton.buttonWithType(.System) as UIButton)
}

You could be more swift-ish like so:

var buttons:[UIButton] = Array(Range(1...10)).map( { $0; return UIButton.buttonWithType(UIButtonType.System) as UIButton } )

I'm not entirely sure why I needed to add $0; to the front of that closure, but it refused to work without it. Luckily, it doesn't do anything.

Ian MacDonald
  • 13,472
  • 2
  • 30
  • 51
  • Okay thank you and is there anyway to set up some sort of delay to the CADisplayLink like you can do with the UIView.AnimateWithDuration so that all the buttons animate at different times? – Garret Kaye Mar 03 '15 at 22:42