Call methods on UIButton objects in NSMutableArray Objective-C - ios

I have an array called buttons which consists of UIButton objects. I populate it as follows:
for (int i=0; i<self.numButtons; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:#selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Title" forState:UIControlStateNormal];
button.frame = CGRectMake(xCoord-40, y, 80, 20);
[button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[button setTag:i];
[self.buttons addObject:button];
[self.view addSubview:button];
y+= 45;
}
The action for these buttons is buttonAction. This action is supposed to change the color of the selected button. Here is how I have it implemented:
-(void) buttonAction:(id)sender{
int num = (int)[sender tag];
[[self.buttons objectAtIndex:num] setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
NSLog(#"%#", [self.buttons objectAtIndex:buttonClicked].titleLabel.text);
}
The result is that there is no color change. Even when I try to NSLog the title of the button it returns (null). So my question is how can I fix this but also how do I call methods on objects inside arrays? Any help would be appreciated. Thanks!

All evidence points to self.buttons being nil. Did you ever initialize it?
Somewhere you need a line like:
self.buttons = [NSMutableArray array];
Of course you could use the sender parameter to your buttonAction: method:
- (void)buttonAction:(UIButton *)button {
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
Note the change in the parameter.

I like to do this. Don't forget to use IBAction. It will help if you decide to use a nib or storyboard.
-(IBAction) buttonAction:(id)sender{
[((UIButton*)sender) setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]
NSLog(#"%#", ((UIButton*)sender).titleLabel.text)
}

Related

Effectively release UIButton memory

I have the following function which creates a custom button. Every time I call initKeyboard(), It is called 14 times. In the course of my app, the user presses a button which calls initKeyboard many times. Every time the user presses the button, I call clearButtonArray().
I noticed that the memory in use goes up gradually, and when it reaches 200MB or so I do see some visual slowdown in my app. Animations are not smooth, etc.
My question is, how do I effectively release the memory used by the 14 buttons everytime. It looks like clearButtonArray() is not doing the job.
I am using ARC.
Thank you for your help.
- (void)initKeyboard:(int)scaleNo
{
[self clearButtonArray];
// call createGlideButton 14 times...
}
- (void)createGlideButton:(int)noteVal
string:(NSString *)noteStr
keyMod:(int)key
chromatic:(BOOL)chrOn
x:(int)xPos
y:(int)yPos
{
GlideButton *button = [GlideButton buttonWithType:UIButtonTypeCustom];
[button setTag:noteVal + key];
[button setUserInteractionEnabled:YES];
[button addTarget:self
action:#selector(notePressedDown:withEvent:)
forControlEvents:UIControlEventTouchDown];
[button addTarget:self
action:#selector(notePressedUp:withEvent:)
forControlEvents:UIControlEventTouchUpInside];
[button addTarget:self
action:#selector(notePressedUp:withEvent:)
forControlEvents:UIControlEventTouchUpOutside];
[button addTarget:self
action:#selector(notePressedUp:withEvent:)
forControlEvents:UIControlEventTouchDragExit];
[button addTarget:self
action:#selector(notePressedUp:withEvent:)
forControlEvents:UIControlEventTouchCancel];
[button addTarget:self
action:#selector(notePressedUp:withEvent:)
forControlEvents:UIControlEventTouchDragOutside];
UIImage *buttonbkImage = [UIImage imageNamed:#"TF8UIElements_smallKeysBtn"];
UIImage *buttonlightImage = [UIImage imageNamed:#"TF8_smallKeysBtnBright"];
[button setBackgroundImage:buttonbkImage forState:UIControlStateNormal];
[button setBackgroundImage:buttonlightImage
forState:UIControlStateHighlighted];
[KeyboardView addSubview:button];
[_buttonArray addObject:button];
}
-(void)clearButtonArray
{
for (int i=0; i < [_buttonArray count]; i++)
{
[[_buttonArray objectAtIndex:i] removeFromSuperview];
[[_buttonArray objectAtIndex:i] setImage:nil forState:UIControlStateNormal];
[[_buttonArray objectAtIndex:i] setImage:nil forState:UIControlStateHighlighted];
}
[_buttonArray removeAllObjects];
}
Remove all the targets of the UIButton before removing it, to avoid keep references.
[[_buttonArray objectAtIndex:i] removeTarget:nil
action:NULL
forControlEvents:UIControlEventAllEvents];
I would recommend to remove them all at once from the KeyboardView and not in a for loop.
So if the KeyboardView only has the buttons as subviews:
[[KeyboardView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
[_buttonArray removeAllObjects];
Not really an answer, but in the end I created the unbuttons only once on initialization and changed the properties of the buttons as per my needs.

Creating a UIButton in a subclass of UIButton

I am trying to create a UIButton in a class that is a subclass of UIButton. The reason for this is that it would be easier for my app to do this. I am wondering if it is possible. I am able to create the button, but the action is not working. My selector exists, but is not getting called.
UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(0, kThumbSide - 350, kThumbSide, 16)];
[button2 setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[button2 setTitle:[NSString stringWithFormat:#"%#", [data objectForKey:#"username"]] forState:UIControlStateNormal];
[button2 sizeToFit];
button2.backgroundColor = [UIColor clearColor];
button2.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
button2.font = [UIFont fontWithName:#"Arial" size:15];
[button2 addTarget:delegate action:#selector(showUserViews) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button2];
Hey you are creating an Object of UIButton class not any Class clear???
and your target method are getting wrong Delegate.
try it
[button2 addTarget:self action:#selector(showUserViews) forControlEvents:UIControlEventTouchUpInside];
replace delegate with self for getting showUserViews method in same class
I haven't see any UIButton subclass here, perhaps you've asked your question wrong.
Any way you should do this:
- (void) viewDidLoad {
[super viewDidLoad]
UIButton *b = [[UIButton alloc]initWithFrame:YOUR_DESIRED_FRAME];
[b setBackgroundColor:[UIColor redColor]]
[b addTarget:self action:#selector(bPressed:) forControlEvents:UIControlEventTouchUpInside]
}
- (void)bPressed:(UIButton *)sender {
NSLog(#"b button pressed")
}

How to change title color and background color of dynamic UIButton when clicked and first button should be selected as default?

I have a view and I created some 8 dynamic buttons programmatically in that. The title color of buttons is white color. I want to change color of button title to green color when it is clicked. And if i click any other button, the previously clicked button title color should become white and current button title color should become green.
I have used the following code and its working properly for changing the color of previous button and now I want the first button to be in selected mode as default and first button should be changed when another button is clicked.
- (void)viewDidLoad
{
_examsListDict1 = [[NSMutableDictionary alloc]init];
_examsListDict1[#"Exam Name"] = #"JEE Mains";
.........so on another 4 dictionaries
_examsListArray = [[NSMutableArray
alloc]initWithObjects:_examsListDict1,_examsListDict2,_examsListDict3,_examsListDict4,_examsListD
ict5, nil];
NSUInteger i;
int xCoord=0;
int yCoord=0;
int buttonWidth=120;
int buttonHeight=50;
int buffer = 1;
for (i = 0; i <[_examsListArray count]; i++)
{
aButton = [UIButton buttonWithType:UIButtonTypeCustom];
aButton.frame = CGRectMake(xCoord, yCoord,buttonWidth,buttonHeight );
[aButton setTitle:[[_examsListArray objectAtIndex:i] objectForKey:#"Exam Name"]
forState:UIControlStateNormal];
[aButton setTag:i];
[aButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[aButton setBackgroundColor:[UIColor colorWithRed:250.0f/255.0f green:255.0f/255.0f
blue:221.0f/255.0f alpha:1]];
[aButton addTarget:self action:#selector(whatever:)
forControlEvents:UIControlEventTouchUpInside];
[_buttonsHorizontalScrollView addSubview:aButton];
xCoord += buttonWidth + buffer;
}
[_buttonsHorizontalScrollView
setContentSize:CGSizeMake(aButton.frame.size.width*_examsListArray.count+203, yCoord)];
}
- (void)whatever:(id)sender
{
UIButton *tempBtn = (UIButton *)sender;
[aButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[aButton setBackgroundColor:[UIColor colorWithRed:250.0f/255.0f green:255.0f/255.0f
blue:221.0f/255.0f alpha:1]];
aButton = tempBtn;
[aButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[aButton setBackgroundColor:[UIColor colorWithRed:133.0f/255.0f green:169.0f/255.0f
blue:83.0f/255.0f alpha:1]];
}
No I just want the first button to be selected as default when the view is loaded and whenever I select the other button it should change to deselected color.
if ([aButton tag] == 0)
{
[aButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[aButton setBackgroundColor:[UIColor colorWithRed:133.0f/255.0f green:169.0f/255.0f
blue:83.0f/255.0f alpha:1]];
}
I have used the above code to select as first button as default but first button is not getting changed when other button is clicked and it is changing only when the first button is clicked again due to this aButton = tempBtn.How to do that?
I suggest you to set the selected status title color of all your buttons and then add them to an array. Then when you press one of them just change their status, no need to handle colors or keep track of the currently selected button.
#property (strong, nonatomic) NSMutableArray *yourButtons;
- (void)viewDidLoad {
[super viewDidLoad];
_examsListDict1 = [[NSMutableDictionary alloc]init];
_examsListDict1[#"Exam Name"] = #"JEE Mains";
.........so on another 4 dictionaries
_examsListArray = [[NSMutableArray alloc] initWithObjects:_examsListDict1,_examsListDict2,_examsListDict3,_examsListDict4,_examsListDict5, nil];
NSUInteger i;
int xCoord=0;
int yCoord=0;
int buttonWidth=120;
int buttonHeight=50;
int buffer = 1;
// Generate background images
//
UIImage *backgroundImage = [self imageWithColor:[UIColor colorWithRed:250.0f/255.0f green:255.0f/255.0f blue:221.0f/255.0f alpha:1]];
UIImage *selectedBackgroundImage = [self imageWithColor:[UIColor colorWithRed:133.0f/255.0f green:169.0f/255.0f blue:83.0f/255.0f alpha:1]];
// Initialize your array
//
self.yourButtons = [[NSMutableArray alloc] init];
for (i = 0; i < [_examsListArray count]; i++) {
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
aButton.frame = CGRectMake(xCoord, yCoord,buttonWidth,buttonHeight );
[aButton setTitle:[[_examsListArray objectAtIndex:i] objectForKey:#"Exam Name"] forState:UIControlStateNormal];
[aButton setTag:i];
[aButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[aButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
[aButton setBackgroundImage:backgroundImage forState:UIControlStateNormal]
[aButton setBackgroundImage:selectedColorImage forState:UIControlStateSelected]
[aButton addTarget:self action:#selector(whatever:) forControlEvents:UIControlEventTouchUpInside];
[_buttonsHorizontalScrollView addSubview:aButton];
xCoord += buttonWidth + buffer;
// Select the first one
//
if (i == 0)
aButton.selected = YES;
// Add your newly created button to the array
//
[self.yourButtons addObject:aButton];
}
[_buttonsHorizontalScrollView setContentSize:CGSizeMake(aButton.frame.size.width*_examsListArray.count+203, yCoord)];
}
- (void)whatever:(id)sender {
for (UIButton *button in self.yourButtons) {
// Toggle selected flag
//
button.selected = button == sender;
}
}
+ (UIImage *)imageWithColor:(UIColor *)color {
// http://stackoverflow.com/a/24665476/1835155
//
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
TRUEThe unpressed button is UIControlStateNormal while the pressed button is UIControlStateSelected so set the colours you want based on the State. You typically do this in ViewDidload before anyone has a chance to use it - Below is a sample setup:
button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setSelected:YES];
button.frame = CGRectMake(x, y, width, height);
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[button setTitleColor:[UIColor blueColor] forState:UIControlStateSelected];
[button setTitle:#"Button Title" forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundImage:[UIImage imageNamed:#"button.png"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"buttonActive.png"] forState:UIControlStateSelected];
[button setBackgroundImage:[UIImage imageNamed:#"buttonActive.png"] forState:UIControlStateHighlighted];
[button setBackgroundImage:[UIImage imageNamed:#"buttonActive.png"] forState:UIControlStateDisabled];
I believe what you should be doing when the trigger button is clicked is to just set the state to selected
- (IBAction)touchDown:(id)sender {
if (sender == trigger_button) {
[button setHighlighted:TRUE];
[button setSelected:TRUE];
}
In order to change the first button state when another button is clicked you have to "fake" a touch event. In the selector method of the other button do this:
For Example:
-(void)thirdButtonClicked:(id) sender
{
[firstButton sendActionsForControlEvents: UIControlEventTouchUpInside];
}

how to select all inside IBOutletCollection

I created a IBOutletCollection property and action for button1 to button9. Each and every button is pressed color will change,
-(IBAction)btnCollectionAction:(id)sender {
counter = 0;
btnSelecter = sender;
if (counter == 0) {
[btnSelecter setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
counter = 1;
}
else {
[btnSelecter setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
counter = 0;
}
}
IBOutlet for selectall button,
- (IBAction)selectButtonFunction1:(id)sender {
if (counter == 0) {
[selBtn1 setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
counter = 1;
}
else {
[selBtn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
counter = 0;
}
}
the above both script works well.
My question is - if i pressed the select all button (change to whiteColor), the above all nine button must change to whiteColor else blackColor.
I tried like this:
if(selBtn1.touchInside) {
[btnSelecter setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
else {
[btnSelecter setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
it will change only one button instead of all.
Last part of your question is vague, I didn't understand the last portion. From your title I understand that you need to get all the UIButton from IBOutletCollection. I'm answering for that question.
You can toggle the color like:
- (IBAction)selectAll:(id)sender
{
for (UIButton *button in buttonCollection)
{
if([button titleColorForState:UIControlStateNormal] isEqual:[UIColor blackColor]])
{
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
}
else
{
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
}
}
Try this approach:
1. Create IBOutletCollection with all your buttons (You Allready done this)
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *myButtons;
2. Iterate throughout collection to configure target and appearence for each button:
for (UIButton *button in self.myButtons)
{
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
// Do any additional configuration here
}
3. Add target to selectAll button and assign Tag property for selectAll button
[selecAllButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
selectAllButton.tag = 10000; // you can other tag number
4. Create buttonPressed: Handler
-(void) buttonPressed:(UIButton *)sender
{
if(sender.tag = 10000)
{
for (UIButton *button in self.menuButtons) {
if([button isKindOfClass:[UIButton class]]){
button.selected = YES;
}
}
} else
{
// handle other button actions
}
}

How to make a custom UIButton with a unique image and selector for each from an array?

I have several UIButtons created from an NSMutableArray. I'm trying to customize each UIButton with a unique image.
On the following line I'm not sure of the syntax to use to set an image for each button from the image array respectively:
[btn setImage:[UIImage imageNamed:[myImages objectAtIndex:3]] forState:UIControlStateNormal];
here's the rest of my code:
NSMutableArray* buttonArray = [[NSMutableArray alloc] init];
for(int i = 0; i < 8; i++)
{
// Custom UIButton
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setFrame:CGRectMake(0.0f, 2.0f, 52.0f, 52.0f)];
[btn setTitle:[NSString stringWithFormat:#"Button %d", i+1] forState:UIControlStateNormal];
NSArray * myImages = [NSArray arrayWithObjects:#"category0.png", #"category-clothing1.png" , #"category2.png", #"category3.png", nil];
[btn setImage:[UIImage imageNamed:[myImages objectAtIndex:3]] forState:UIControlStateNormal];
[btn addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[buttonArray addObject:btn];
}
I would also like a different selector to be called for each button.
Something like this? I just saw your post about needing different actions for each button but I would instead check the sender of the button and adjust the code accordingly inside your (buttonPressed:) method. You should also make sure you have the appropriate amount of images for your button array so a better method may be to only create the amount of buttons based on your image array count. (answer edited to reflect this). I also wanted to add you should get in the habit of also changing the highlighted state of the image when changing the normal state so when you press the image it doesn't go blank.
NSMutableArray* buttonArray = [NSMutableArray array];
NSArray * myImages = [NSArray arrayWithObjects:#"category0.png", #"category-clothing1.png" , #"category2.png", #"category3.png", nil];
for(int i = 0;i < [myImages count]; i++)
{
// Custom UIButton
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setFrame:CGRectMake(0.0f, 2.0f, 52.0f, 52.0f)];
[btn setTitle:[NSString stringWithFormat:#"Button %d", i] forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:[myImages objectAtIndex:i]] forState:UIControlStateHighlighted];
[btn setImage:[UIImage imageNamed:[myImages objectAtIndex:i]] forState:UIControlStateNormal];
[btn addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[buttonArray addObject:btn];
}
This code contains image and selectors from array.
(This code is not compiled-check, may contain some small issue, sorry for inconvenience)
NSMutableArray* buttonArray = [NSMutableArray array];
NSArray * myImages = [NSArray arrayWithObjects:#"category0.png", #"category-clothing1.png" , #"category2.png", #"category3.png", nil];
// You need to assign string name and that should be your method name.
NSMutableArray *selectors=[[NSMutableArray alloc]initWithArray:#"sel1",#"sel2",#"sel3",#"sel4", nil];
for(int i=0; i<[myImages count]; i++){
// Custom UIButton
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setFrame:CGRectMake(0.0f, 2.0f, 52.0f, 52.0f)];
[btn setTitle:[NSString stringWithFormat:#"Button %d", i] forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:[myImages objectAtIndex:i]] forState:UIControlStateHighlighted];
[btn setImage:[UIImage imageNamed:[myImages objectAtIndex:i]] forState:UIControlStateNormal];
SEL selector = selectorFromString([selectors objectAtIndex:i]);
[btn addTarget:self action:#selector(selector) forControlEvents:UIControlEventTouchUpInside];
[buttonArray addObject:btn];
}

Resources