100

I have a UIButton, that when pressed, brings up a new view where the user can change some settings. When the view is dismissed, I'd like to update the title/text of the UIButton to reflect the new state. I'm calling:

[myButton setTitle: @"myTitle" forState: UIControlStateNormal];
[myButton setTitle: @"myTitle" forState: UIControlStateApplication];
[myButton setTitle: @"myTitle" forState: UIControlStateHighlighted];
[myButton setTitle: @"myTitle" forState: UIControlStateReserved];
[myButton setTitle: @"myTitle" forState: UIControlStateSelected];
[myButton setTitle: @"myTitle" forState: UIControlStateDisabled];

But it never seems to change from the original text/title as specified in IB.

TheNeil
  • 3,321
  • 2
  • 27
  • 52
George Armhold
  • 30,824
  • 50
  • 153
  • 232
  • 2
    Are you sure the posted code is being called? Did you place a BREAKPOINT to prove that? Can you post your delegate's signature? – Pablo Santa Cruz Jun 23 '09 at 16:42
  • 3
    As an aside, I believe you can reference multiple control states at once: [ myButton setTitle:@"myTitle" forState:( UIControlStateNormal | UIControlStateApplication | UIControlStateHighlighted | ... ) ]; Note the use of the bitwise OR operator as opposed to the logical OR operator (||). In general, when you're dealing with states like this, you can OR them together with the | operator. Someone correct me if I'm grossly mistaken. :) – CIFilter Jun 25 '09 at 03:18
  • I wish they had one like UIControlStateAll :D – taber Dec 31 '10 at 06:54
  • 2
    The bitwise combinations don't seem to work for me in iOS5. – Echilon Feb 15 '12 at 20:14
  • Same issue here. Bitwise combinations don't work for me on iOS5. /CC @LucasTizma – znq Sep 22 '12 at 13:28
  • I'm not having any issues combining states in iOS 5 or 6. Be careful to remember that when you tap on a button, its state is momentarily set to `UIControlStateHighlighted | UIControlStateSelected`, which makes sense when you tap the control. Afterwards, its state is just `UIControlStateSelected`. – CIFilter Sep 24 '12 at 20:09

12 Answers12

115

I solved the problem just setting the title parameter for UIControlStateNormal, and it automatically works on the other states. The problem seems to be when you set another UIControlState.

[myButton setTitle: @"myTitle" forState: UIControlStateNormal];
shim
  • 9,289
  • 12
  • 69
  • 108
Yotes
  • 1,151
  • 2
  • 7
  • 2
52

Do you have the button specified as an IBOutlet in your view controller class, and is it connected properly as an outlet in Interface Builder (ctrl drag from new referencing outlet to file owner and select your UIButton object)? That's usually the problem I have when I see these symptoms.


Edit: While it's not the case here, something like this can also happen if you set an attributed title to the button, then you try to change the title and not the attributed title.

Lord Zsolt
  • 6,492
  • 9
  • 46
  • 76
Ken Pespisa
  • 21,989
  • 3
  • 55
  • 63
  • 4
    Bingo, that was it, thanks. I really wish Objective-C would just throw a NullPointerException in cases like this, instead of silently pretending that it's OK to send a message to a nil object. This bites me almost daily... ugh! – George Armhold Jun 23 '09 at 17:26
  • 20
    ObjC doesn't 'pretend' its OK to send a message to nil, because it *is* OK to send messages to nil... – Jasarien Jun 23 '09 at 23:27
  • 1
    The issue here is not a nil pointer. The issue is that IB has setup a UIButton instance that isn't being referenced properly in the code (via IBOutlet), so it can never be manipulated programmatically. – CIFilter Jun 25 '09 at 03:13
18

As of Swift 4:

    button.setTitle("Click", for: .normal)
Max MacLeod
  • 26,115
  • 13
  • 104
  • 132
Allan Spreys
  • 5,287
  • 5
  • 39
  • 44
13

I discovered another problem. It may be a bug introduced in iOS 5, but I thought I'd point it out for anyone else who encounters it.

If you don't set any default text for the button in the XIB, no text will ever appear if you set it programmatically. And if you do set text in the XIB, any text you subsequently assign to the button programmatically will be truncated to the size of the default text.

And finally, if you're showing the view with your button and then invoke another view (like an ActionSheet) and then dismiss it, the text that you assigned to the button programmatically will be erased and the button caption will return to whatever you set up in the XIB.

Oscar
  • 2,039
  • 2
  • 29
  • 39
  • 1
    I have noticed all three of these behaviors and it is certainly annoying. – Flea May 16 '12 at 17:56
  • 2
    I had the truncation issue (changing the text to something longer programmatically), so I put extra spaces on the end of the text to 'reserve' that space for when I change the text to a longer word. That worked for me. – mattorb Nov 15 '12 at 21:36
  • 2
    It appears that the fix for this is to use the method [_button setTitle: @"title" forState: UIControlStateNormal]; instead of accessing the _button.titleLabel.text property directly. Stick with the method call and you'll probably get what you want. – Rymnel Jan 16 '14 at 21:53
12

Even though Caffeine Coma's issue was resolved, I would like to offer another potential cause for the title not showing up on a UIButton.

If you set an image for the UIButton using

- (void)setImage:(UIImage *)image forState:(UIControlState)state

It can cover the title. I found this out the hard way and imagine some of you end up reading this page for the same reason.

Use this method instead

- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state

for the button image and the title will not be affected.

I tested this with programmatically created buttons and buttons created in a .xib

Jesse Black
  • 7,966
  • 3
  • 34
  • 45
8

for swift :

button.setTitle("Swift", forState: UIControlState.Normal)                   
Sangram Shivankar
  • 3,535
  • 3
  • 26
  • 38
Dara Tith
  • 518
  • 7
  • 21
4

One more possible cause is this:

If you attempt to set the button's title in the (id)initWithNibName: ... method, then you're button property will still be nil. It hasn't yet been assigned to the UIButton.

You must be sure that you're setting your buttons in a method like (void)viewWillLoad or (void)viewWillAppear, but you probably don't want to set them as late as (void)viewDidAppear.

Paolo Bernasconi
  • 2,010
  • 11
  • 35
  • 54
Ramsey
  • 41
  • 1
4

Turns out the docs tell you the answer! The UIButton will ignore the title change if it already has an Attributed String to use (with seems to be the default you get when using Xcode interface builder).

I used the following:

[self.loginButton 
     setAttributedTitle:[[NSAttributedString alloc] initWithString:@"Error !!!" attributes:nil] 
     forState:UIControlStateDisabled];
[self.loginButton setEnabled:NO];
CPD
  • 427
  • 2
  • 11
2

Sometimes it can get really complicated. The easy way is to "refresh" the button view!

//Do stuff to your button here.  For example:

[mybutton setEnabled:YES];

//Refresh it to new state.

[mybutton setNeedsDisplay];
Mike Rapadas
  • 4,613
  • 2
  • 28
  • 21
1

I kept having problems with this, the only solution was to add an image and label as subviews to the uibutton. Then I discovered that the main problem was that I was using a UIButton with title: Attributed. When I changed it to Plain, just setting the titleLabel.text did the trick!

Mark
  • 379
  • 3
  • 7
1

@funroll is absolutely right. Here you can see what you will need Make sure function runs on main thread only. If you do not want deal with threads you can do like this for example: create NSUserDefaults and in ViewDidLoad cheking condition was pressed button in another View or not (in another View set in NSUserDefaults needed information) and depending on the conditions set needed title for your UIButton, so [yourButton setTitle: @"Title" forState: UIControlStateNormal];

Community
  • 1
  • 1
daleijn
  • 718
  • 13
  • 22
  • This was very useful to me.. turns out if you call setTitle and setNeedsDisplay from a background thread the View will get updated much later. – p.sherif Nov 14 '16 at 02:51
0

Make sure you're on the main thread.

If not, it will still save the button text. It will be there when you inspect the object in the debugger. But it won't actually update the view.

funroll
  • 35,925
  • 7
  • 54
  • 59