2

After looking over the internet and other SO questions(this one is great iOS: UIButton titleLabel -- does it do anything at all?), it is unclear to me what is the difference between these two, more accurately, how these two work.

I know that setTitle:forState: let me set text of the button for different states(Normal, Disabled,Highlighted etc.). I know, as well, that titleLabel is read only, but its properties are read/write.

At this point you might ask: What is the problem then?

I will explain it through example. I have following hierarchy:

UITableViewCell - MyView - MyButton

MyView is xib in which, through interface builder, I set button. When I set buttons title like:

self.myButton.titleLabel.text = @"Something"; // some string I get from server

It works. But if I try the similar approach when only MyView is included (somewhere else in the project) and try:

myView.myButton.titleLabel.text = @"Something else";

It doesn't work. Let me be more specific. In one part of the second(even in viewDidApper) buttons title is what I want. After that, the buttons label returns to its default value. The one I set in the interface builder. When I change to

[myView.myButton setTitle:@"Something else" forState:UIControlStateNormal];

It works as expected.

What I want to know is why does this happen? It is unclear to me why does this glitch occurs with the title? Is this strange thing documented somewhere(looked over apple documentation)? Is it possible to get implementation of setTitle:forState:?

Community
  • 1
  • 1
Miknash
  • 7,888
  • 3
  • 34
  • 46

3 Answers3

2

I'm not sure how the internals of UIButton are actually implemented but this is a guess. There are times when iOS needs to redraw the button ie. the button is tapped so the button's state changes (let's say from UIControlStateNormal to UIControlStateHighlighted). Then iOS would find the title associated to UIControlStateHighlighted then display that text by using something like.

myButton.titleLabel.text = @"Title for UIControlStateHighlighted";

Sample scenario:

[myButton setTitle:@"Normal" forState:UIControlStateNormal];
[myButton setTitle:@"Highlighted" forState:UIControlStateHighlighted];

// somewhere in the code, you call this to change the label
myButton.titleLabel.text = @"Something else";

// when user taps the button, iOS will do something like
myButton.titleLabel.text = @"Highlighted"; // will overwrite "Something Else"

// when user releases, iOS will again do something like
myButton.titleLabel.text = @"Normal"; // will overwrite "Highlighted"

so it's required to use setTitle:forState: in order to associate the given title to a certain state. The instances where iOS redraws the button is of course not limited to the the user interacting with the button. It could also be triggered by layout changes.

1

You should not use button.titleLabel.text = to set the button title.

The documentation for the titleLabel property says

Although this property is read-only, its own properties are read/write. Use these properties primarily to configure the text of the button. For example:

UIButton *button                  = [UIButton buttonWithType:UIButtonTypeSystem];
button.titleLabel.font            = [UIFont systemFontOfSize: 12];
button.titleLabel.lineBreakMode   = NSLineBreakByTruncatingTail;

Do not use the label object to set the text color or the shadow color. Instead, use the setTitleColor(:for:) and setTitleShadowColor(:for:) methods of this class to make those changes. To set the actual text of the label, use setTitle(_:for:) (button.titleLabel.text does not let you set the text).

trapper
  • 11,716
  • 7
  • 38
  • 82
-1

I normally don't set button titles in interface builder, but do it in the viewDidLoad, and get the title from Localizable.strings..

You must use setTitle:forState and setTitleColor:forState to change text and color. All other label properties can be changed directly though.

"Do not use the label object to set the text color or the shadow color. Instead, use the setTitleColor:forState: and setTitleShadowColor:forState: methods of this class to make those changes." -source

dOM
  • 555
  • 5
  • 14
  • Yeah, I know that I must use forState functions, but my question is why? And why does it work one way and doesn't work around? For translations you can use translated storyboards and assign strings via ID's(when you translate it you get everything ready, you just have to set text). Thanks for your answer. – Miknash Apr 08 '15 at 14:26
  • @NickCatib just a UIButton thing, you need to set the titles based on state, as required by UIButton. – Schemetrical Apr 08 '15 at 16:35
  • @Schemetrical , do you have a link that actually supports thesis that this approach is required by UIButton? and, if thats the case, why does button.titleLabel.text works in some cases at all? – Miknash Apr 09 '15 at 10:31
  • @NickCatib I actually have nothing to back myself up, but I know from working `UIButton`s that the errors while using `button.titleLabel.text` disappear when I use the designated setter through `-setTitle:forState:`. I'm assuming without the state, setting the title individually will bypass some `UIButton` internal code. That's just my guess. – Schemetrical Apr 09 '15 at 10:41
  • @Schemetrical I agree, as I said in my question I am very aware what I should use set for state, I just want to know why. There seems to be very little information about that – Miknash Apr 09 '15 at 10:50
  • The documentation says "To set the actual text of the label, use setTitle(_:for:) (button.titleLabel.text does not let you set the text)." – trapper Oct 09 '19 at 03:03