View Full Version : How to change a button's title when it has already been subview(ed)

Apr 20, 2011, 08:18 PM
So I'm trying to change a button's title after it has been added into another view. A gave it a tag so I can call it but it's not working.

Button code

CGRect frame = CGRectMake(100.0, 70.0, 100.0, 35.0);
UIImage *blueImage = [UIImage imageNamed:@"blue_button.png"];
UIImage *blueButtonImage = [blueImage stretchableImageWithLeftCapWidth:7 topCapHeight:0];

UIButton *btn = [[UIButton alloc] initWithFrame:frame];

[btn setTitle:@"CaSO4" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor blackColor] forState:UIControlEventTouchDown];
btn.titleLabel.font = [UIFont boldSystemFontOfSize:12.0];
[btn setTitleEdgeInsets:UIEdgeInsetsMake(0.0, 0.0, 0.0, 10.0)];
[btn setBackgroundImage:blueButtonImage forState:UIControlStateNormal];
btn.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
[btn addTarget:self action:@selector(slideButton:) forControlEvents:UIControlEventTouchUpInside];
btn.tag = 102;
[self.view addSubview:btn];
[btn release];

Method to change the title

- (void)setButton:(NSString *)label
[[self.view viewWithTag:102] setTitle:label forState:UIControlStateNormal];


The warning is 'UIView' may not respond to 'SetTitle:forState'
Which is true... I'm trying to target the button and not the view.


Apr 21, 2011, 04:58 AM
Assuming that there is only ever one view with tag 102 then you can just case the result to the correct type. Given that you've not done that already I'll assume you don't know what that means (sorry if you do). In general a cast looks like:

((MyType) var)

This tells the compiler to treat var as type MyType. Note that this does not actually change the type of var. If it's impossible to perform the cast then this will fail. In terms of object pointers you can suppress the compiler warning but still have runtime errors (for example you could cast and id typed var to any NSObject * subtype but it doesn't make var the correct object). So you should only do this when you are 100% sure your cast is correct.

In this case you want code that looks like this:

- (void)setButton:(NSString *)label
[((UIButton *) [self.view viewWithTag:102]) setTitle:label forState:UIControlStateNormal];


I would note that there are ways to make this less brittle. You could check the class of the returned UIView (using a variable to store the view pointer). Or you could check if the UIView responds to the -setTitle:forState: message and send it via -performSelector:withObject:withObject:

Apr 21, 2011, 07:06 AM
Sometimes setting a tag with:

myButton.tag = 1;

does not actually set the tag properly but I'd have to do

[myButton setTag:1];


you could try

self.myButton.tag = 1;

Apr 21, 2011, 11:23 AM
I tried casting it. That got rid of the warning but the button title doesn't change.

- (void)setButton:(NSString *)label

[((UIButton *)[self.view viewWithTag:102]) setTitle:label forState:UIControlStateNormal];

if([self.view viewWithTag:102]) {
NSLog(@"I exist");

NSLog(@"%@", label);

I even checked to see if view tag:102 exists, which it does :)

I'll try the saving the view to a pointer and performSelector suggestions next.

Apr 21, 2011, 11:46 AM
I'll try the saving the view to a pointer and performSelector suggestions next.

That won't make any difference. That was simply a suggestion on style/modularity. You're check that the view with tag 102 is incorrect. You should be doing:

if([self.view viewWithTag:102]!=nil) {
NSLog(@"I exist");

Apr 21, 2011, 12:04 PM
You should be doing:

if([self.view viewWithTag:102]!=nil) {
NSLog(@"I exist");

As well as putting the code that sets the title inside the if. Doesn't make much sense to check the view existence after you've already tried to use it.

Apr 21, 2011, 03:09 PM
Also, when dealing with UIButton it's usually best to create one in code using:

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

You can replace the button type with whichever type you need (e.g. UIButtonTypeRoundedRect). Make sure you set the frame of the button after initializing a new one.

Apr 21, 2011, 05:30 PM
whoa, something really strange...
I modified it to this..

if([self.view viewWithTag:102] != nil) {
NSLog(@"I exist");
UIButton *bttn = (UIButton *)[self.view viewWithTag:102];
[bttn setTitle:label forState:UIControlStateNormal];
NSLog(@"%@", [bttn titleForState:UIControlStateNormal]);

I wanted to see what the title of the button is and the title on the button DOES change in code but not visually in the view. Does the view need to be refreshed or something?


Thanks for the help guys. I made a simpler project with these exact code and it works.... My bigger project must be breaking this somewhere. I'll have to dig through the code.


I found the problem. I'm calling this method 'setButton' from a pickerview in another view. I made a delegate to call setButton and it working's correctly now. It's weird that the method does get called normally with instantiating, [[myClass alloc] init] setButton] but needed a delegate to work correctly.