0

this is my first project, and i try to set a button title for some time and after it should reset. This my code:

The first (test) snippet simply tries to set immediately to "tapped" and then after 2 secs to reset to "tap me". What i see is disappering the button for 2sec and then only "tap me" again!?

    @IBOutlet weak var button1: UIButton!
@IBAction func button1Tapped(sender: UIButton) {
    sender.setTitle("tapped", forState: .Highlighted)
    NSThread.sleepForTimeInterval(2.0)
    sender.setTitle("tap me", forState: .Normal)
}

The second example is more what i really want! But for some reason I immediately fail here, because the alert simply does not show up!?

Any hints?

    @IBOutlet weak var button2: UIButton!
@IBAction func button2Tapped(sender: AnyObject) {
}

func isOK(sender:UIAlertAction!){
    button2.setTitle("tapped", forState: .Normal)
    NSThread.sleepForTimeInterval(2.0)
    button2.setTitle("tap me", forState: .Normal)
}

func isCancel(sender:UIAlertAction!){
}

@IBAction func button2Tapped(sender: UIButton) {
    let alert = UIAlertController(title: "Test", message: "button", preferredStyle: UIAlertControllerStyle.Alert)
    alert.addAction(UIAlertAction(title:"OK", style: UIAlertActionStyle.Default, handler: isOK))
    alert.addAction(UIAlertAction(title:"Cancel", style: UIAlertActionStyle.Cancel, handler: isCancel))
    self.presentViewController(alert, animated: true, completion: nil)
}

OK, i changed to this:

    @IBOutlet weak var button1: UIButton!
@IBAction func button1Tapped(sender: UIButton) {
    sender.selected = true
    NSThread.sleepForTimeInterval(2.0)
    sender.selected = false
}
override func viewDidLoad() {
    super.viewDidLoad()
    button1.setTitle("tapped", forState: .Selected)
    button1.setTitle("tap me", forState: .Normal)
}

but it shows the same behaviour. Actually it shows "tapped" but only when i keep pressing!?

pawi
  • 2,173
  • 3
  • 13
  • 15

2 Answers2

0

Firstly, delete all the code you have written. Instead, use this code that I have taken from answer of Matt. Credits goes to him. This function is needed to "delay" the action of something.

func delay(delay:Double, closure:()->()) {
dispatch_after(
    dispatch_time(
        DISPATCH_TIME_NOW,
        Int64(delay * Double(NSEC_PER_SEC))
    ),
    dispatch_get_main_queue(), closure)
}

Now create an @IBAction connection:

@IBAction func button(sender: AnyObject) {
// Okay, the button has been tapped
  button.setTitle("tapped", forState: .Normal)

// after two seconds...
  delay(2.0) {

// change the button's title:
  button.setTitle("tap here!", forState: .Normal)

  }
}
Community
  • 1
  • 1
Cesare
  • 8,326
  • 14
  • 64
  • 116
  • i copied your code and used it as posted! The title "tapped" does not show up!? It only required me to add "self." to: self.button1.setTitle("tap here!", forState: .Normal) – pawi Jan 23 '15 at 15:59
  • Try using both `.Selected` or both `.Normal` after `forState:`. Also are you getting any errors? – Cesare Jan 23 '15 at 16:02
  • Aha! both .Normal works! Do you have an explanation for that? – pawi Jan 23 '15 at 16:06
  • Glad you got it working! In Swift we use `.Selected` if we want to change the image of the button. Especially in games if you press a button you see an push-over effect. Please check this image: http://i.stack.imgur.com/KLjOP.png. In this case, `.Normal` is always needed because you aren't changing the image of the button. – Cesare Jan 23 '15 at 16:09
0

One of the problems with the first way that you attempted is that you have simply set the title for two different states of sender: .Highlighted and .Normal. If you never change the state of sender, you'll only ever see the title associated with its current state (.Normal by default).

You could update the title for the same state twice to get the behaviour you want, or you might consider using the .Selected state of the button, depending on your application's implementation and usage of the button.

// Call these two setTitle lines wherever you are instantiating your button
// or otherwise setting up your view:
sender.setTitle("tapped", forState: .Selected)
sender.setTitle("tap me", forState: .Normal)

// Somewhere else, you can call either of these:
sender.selected = YES // sender now shows "tapped"
sender.selected = NO  // sender now shows "tap me"

Secondly, we need to address your threading issues.

At some point, the main thread has been scheduled to run the code contained within your isOK method. It also has work scheduled to update the UI. Your main thread's queue might look something like this:

(0): __ execute isOK(..)
(1): __ do some other stuff
(2): __ update the UI
(3): __ do some other stuff

If you update your UI in (0) and then update it again in (0), the first update won't be seen because the queue hasn't been allowed to progress to (2) in between. When you NSThread.sleepForTimeInterval() in (0), you are delaying UI updates and freezing your app.

Instead, you'll want to put your sleep into a different queue and then inject your following commands back onto the main thread after your duration has elapsed.

You can do this in a few ways, but the easiest way is to use GCD (Grand Central Dispatch) and dispatch_after.

@IBAction func button1Tapped(sender: UIButton) {
  sender.selected = YES
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))),
                 dispatch_get_main_queue(), ^{
    sender.selected = NO
  });
}
Ian MacDonald
  • 11,433
  • 1
  • 21
  • 41
  • But isn't the code in isOK not scheduled only after the alert should have come up? Why do i not see the alert? – pawi Jan 23 '15 at 15:56
  • I'm not sure exactly what you're asking. You've changed your implementation around quite a bit. In order to change your button text and then change it back 2 seconds later, you just need to set it, then call `dispatch_after` and unset it within the block you provide. – Ian MacDonald Jan 23 '15 at 16:13
  • Sorry, but my examples are propably misleading. These are actually independent. With the first snippet i wanted to test the settings of the button, independent of the second example with the alert. Did you refer with your first code also to a threading problem!? I tried your first code, but this didn't work! My second example does not even show the alert!? – pawi Jan 23 '15 at 16:23
  • In your post, you have written some code after "OK, i changed to this:". This should be using the `button1Tapped` that I wrote at the end of my answer. Your `button2Tapped` is showing your alert possibly because you have defined the function twice and the first one is empty. – Ian MacDonald Jan 23 '15 at 16:27
  • Sorry, i misunderstood your solution for example "button1". This works with your and CeCExx proposal. Thanks! But what with my second example "button2"? I can't see where i defined the function twice. – pawi Jan 23 '15 at 16:40
  • Sorry again! I just looked at my code more thoroughly. You are right, i declared the function twice. Stupid! – pawi Jan 23 '15 at 16:54