Effectively release UIButton memory - ios

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.

Related

Call methods on UIButton objects in NSMutableArray Objective-C

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)
}

I want to change the UIButton Highlight Image, but without success

I have a UIbutton in my view
I want to change the UIButton Highlight Image, but without success
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 66, 29)];
[button setBackgroundImage:[UIImage imageNamed:#"filter_button_normal.png"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"filter_button_selected.png"] forState:UIControlStateHighlighted];
[button setBackgroundImage:[UIImage imageNamed:#"filter_button_down_selected.png"] forState:UIControlStateSelected];
[button addTarget:self action:#selector(filterAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
- (void)filterAction:(UIButton *)button
{
if(button.isSelected == YES)
{
[button setBackgroundImage:[UIImage imageNamed:#"filter_button_selected.png"] forState:UIControlStateHighlighted];
button.selected = NO;
}
else
{
#warning I want to change the UIButton Highlight Image, but without success
[button setBackgroundImage:[UIImage imageNamed:#"filter_button_down_normal.png"] forState:UIControlStateHighlighted];
button.selected = YES;
}
}
If you want your button to behave as follows,
normal - filter_button_normal
highlighted (on touch press down on button) - filter_button__down_selected
selected (after removing touch from button) - filter_button_selected;
[button setBackgroundImage:[UIImage imageNamed:#"filter_button_normal.png"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:#"filter_button_selected.png"] forState:UIControlStateSelected];
[button setBackgroundImage:[UIImage imageNamed:#"filter_button_down_selected.png"] forState:UIControlStateHighlighted];
so when the user touches it , image changes to highlighted and when he removes his finger over it, it changes to selected
And the target you added is UIControlEventTouchUpInside
[button addTarget:self action:#selector(filterAction:) forControlEvents:UIControlEventTouchUpInside];
so filterAction is called after the user removes his finger from it.
- (void)filterAction:(UIButton *)button
{
// the image will change automatically
if(button.isSelected == YES)
{
button.selected = NO;
}
else
{
button.selected = YES;
}
}

How to change button image added to TableView section header

I've added a button to section header which shows a view on clicking it. My need is that I've to show an "Up-arrow" image while view is shown and "Down-arrow" image when view is hidden.
How can I achieve this? Please help me ...
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];
[btn setFrame:CGRectMake(0, 0, 316, 60)];
[btn setTag:section];
[aView addSubview:btn];
[btn addTarget:self action:#selector(sectionTapped:) forControlEvents:UIControlEventTouchDown];
btn.backgroundColor=[UIColor clearColor];
}
I will suggest that you can have 2 images - 1 for 'Up' and 1 for 'Down' arrow.
Set default image to the btn for state UIControlStateNormal and set the other image for state UIControlStateSelected.
Now in your sectionTapped: method just change the state of the button.
So when you show or hide your view you need to set the button selected YES/NO.
Hope this helps.
I had done this before in one of my app.
Take this code as Reference
1.Specific Method.
- (void)methodName:(UIButton *)sender
{
int i = [sender.titleLabel.text intValue];
NSNumber *numb;
if(i == 0)
{
numb = [NSNumber numberWithBool:NO];
sender.titleLabel.text = #"1";
[sender setImage:[UIImage imageNamed:#"down.png"] forState:UIControlStateNormal];
[sender setImage:[UIImage imageNamed:#"up.png"] forState:UIControlStateHighlighted];
}
else
{
numb = [NSNumber numberWithBool:YES];
sender.titleLabel.text = #"0";
[sender setImage:[UIImage imageNamed:#"up.png"] forState:UIControlStateNormal];
[sender setImage:[UIImage imageNamed:#"down.png"] forState:UIControlStateHighlighted];
}
}
2.Setting UIButton Programatically in UITabelview viewForHeaderInSection.
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(240, 20, 30, 30)];
[button addTarget:self
action:#selector(methodName:)
forControlEvents:UIControlEventTouchDown];
button.tag = section;
if([[sectionsArray objectAtIndex:section] boolValue])
{
[button setImage:[UIImage imageNamed:#"up.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"down.png"] forState:UIControlStateHighlighted];
button.titleLabel.text = #"0";
}
else
{
[button setImage:[UIImage imageNamed:#"down.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"up.png"] forState:UIControlStateHighlighted];
button.titleLabel.text = #"1";
}
You can trying using BOOL to check if the button has been pressed or not and animate to rotate the image in your button to point up or down.
-(IBAction)dropdownBtnClicked:(id)sender
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
if (!isDropdownEnabled)
{
//BOOL - checking if the button has been pressed or not
isDropdownEnabled=TRUE;
drpDwnBtn.transform=CGAffineTransformMakeRotation(270/180*M_PI);
}
else
{
isDropdownEnabled=FALSE;
drpDwnBtn.transform=CGAffineTransformMakeRotation(0);
}
[UIView commitAnimations];
}

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];
}

Checkbox control for iOS application

Is there any checkbox control in the object library for iOS applications? The nearest thing I see is the switch control, which can take a boolean value.
You can use the selected state of a UIButton, set different images (or also texts) for differents (via code, or Interface Builder) :
[button setImage:[UIImage imageNamed:#"selected.png"]
forState:UIControlStateSelected];
[button setImage:[UIImage imageNamed:#"unselected.png"]
forState:UIControlStateNormal];
And in the touch up inside action :
- (IBAction)buttonTouched:(id)sender
{
button.selected = !button.selected;
// add other logic
}
//define property of button
Declare Unchecked Image
- (void)viewDidLoad
{
[_checkboxButton setBackgroundImage:[UIImage imageNamed:#"unchecked.png"] forState:UIControlStateNormal];
}
Checked Image.
- (IBAction)buttonTapped:(id)sender
{
if (_checkboxButton.selected == YES)
{
[_checkboxButton setBackgroundImage:[UIImage imageNamed:#"unchecked.png"] forState:UIControlStateSelected];
_checkboxButton.selected = NO;
}
else
{
[_checkboxButton setBackgroundImage:[UIImage imageNamed:#"checked.png"] forState:UIControlStateNormal];
_checkboxButton.selected = YES;
}
}
This is the code I use for two checkboxes on the screen. (I put them at the bottom of two pictures that are also on the screen. I use the UIControlEventTouchDown to call the checkBoxTapped method. This method talks to my main view controller where I decide if the answer was correct or incorrect. Then the main view controller calls back the this view and tells it to change the blank textbox to either a check:
or an x
// Put the Checkboxes on the screen
UIImage *checkBox = [UIImage imageNamed:#"Checkbox"];
self.checkBoxLeft = [UIButton buttonWithType:UIButtonTypeCustom];
[self.checkBoxLeft setImage:checkBox forState:UIControlStateNormal];
[self.checkBoxLeft setFrame:checkBoxFrameLeft];
[self.checkBoxLeft addTarget:self
action:#selector(checkBoxTapped:)
forControlEvents:UIControlEventTouchDown];
[self.checkBoxLeft setTitle:#"checkBoxLeft" forState:UIControlStateNormal];
self.checkBoxLeft.contentEdgeInsets = insets;
self.checkBoxLeft.showsTouchWhenHighlighted = NO; // Keeps it from turning gray
self.checkBoxRight = [UIButton buttonWithType:UIButtonTypeCustom];
[self.checkBoxRight setImage:checkBox forState:UIControlStateNormal];
[self.checkBoxRight setFrame:checkBoxFrameRight];
[self.checkBoxRight addTarget:self
action:#selector(checkBoxTapped:)
forControlEvents:UIControlEventTouchDown];
[self.checkBoxRight setTitle:#"checkBoxRight" forState:UIControlStateNormal];
self.checkBoxRight.contentEdgeInsets = insets;
self.checkBoxRight.showsTouchWhenHighlighted = NO; // Keeps it from turning gray
- (void)checkBoxTapped:(UIButton *)buttonPressed {
[[self delegate] checkBoxTapped:buttonPressed.currentTitle];
}
- (void)highlightCheckbox:(NSString *)checkboxToHighlight withHighlight:(NSString *)highlight {
if ( [checkboxToHighlight isEqualToString:#"left"] ){
[self.checkBoxLeft setImage:[UIImage imageNamed:highlight] forState:UIControlStateNormal];
} else {
[self.checkBoxRight setImage:[UIImage imageNamed:highlight] forState:UIControlStateNormal];
}
}

Resources