Why is NSLog causing EXC_BAD_ACCESS? - iphone

I have a tablecell with a button and I want to hook this in to a method call in my main class.
I have it working, but I need to identify the button pressed. SO I have done the following:
in cellForRowAtIndexPath I do the following:
cell.myBtn.tag = indexPath.row;
[cell.myBtn addTarget:self
action:#selector(viewClick:)
forControlEvents:UIControlEventTouchUpInside];
And I created the selector method like so:
- (void)viewClick:(id)sender
{
UIButton *pressedButton = (UIButton *)sender;
// EXC_BAD_ACCESS when running NSLog
NSLog(#"button row %#",pressedButton.tag);
if(pressedButton.tag == 1)
{
// NSString filename = #"VTS_02_1";
}
}
The problem is I get EXC_BAD_ACCESS when it hits this line: NSLog(#"button row %#",pressedButton.tag);

specify %i for int value
you have to use %# for only object, but int is not object,NSNumber is an object for that you can use %#.
NSLog(#"button row %i",pressedButton.tag);

try NSLog(#"button row %d", pressedButton.tag);
tag property is an int not an object.

Related

How to create Multiple buttons programmatically, get button name whenever press on particular button?

I want to create multiple buttons using MutableArray count. After creating the button, whenever pressing on particular button, I want to display that button name in a label. But Once press on button, it is always showing the MutableArray last index value name. Please help in this problem. I am fresher ti iOS. It's my code.
-(void)ViewDidLoad {
NSMutableArray *Mute_array=[[NSMutableArray alloc]initWithObjects:#"One", #"Two", #"Three", #"Four", #"Five", nil];
for (int k=0; k<[Mute_array count]; k++){
UIButton *btn_sub_category = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn_sub_category addTarget:self action:#selector(clicks:) forControlEvents:UIControlEventTouchDown];
[btn_sub_category setTitle:[Mute_Sub_Category objectAtIndex:k] forState:UIControlStateNormal];
btn_sub_category.frame = CGRectMake(278, k*130, 483, 44);
[self.view addSubview:btn_sub_category];
}
}
-(void)clicks:(id)sender{
label.text=[btn_sub_category currentTitle];
//Here a want to send the name of that clicked button current title
}
But, here button current title is always showing MutableArray last object "Five" only. I want pressed button current title.
-(void)clicks:(id)sender{
UIButton *theButton = (UIButton*)sender;
NSString *theButtonTitle = [theButton titleForState:UIControlStateNormal]
NSLog(#"theButtonTitle :- %#", theButtonTitle);
label.text=theButtonTitle;
//Here a want to send the name of that clicked button current title
}
Try this code.
I using following method to get title of button
titleForState:
Returns the title associated with the specified state.
- (NSString *)titleForState:(UIControlState)state Parameters
state
The state that uses the title. The possible values are described in UIControlState.
Return Value
The title for the specified state. If no title has been set for the
specific state, this method returns the title associated with the
UIControlStateNormal state.
Read Documentation https://developer.apple.com/library/ios/documentation/uikit/reference/UIButton_Class/UIButton/UIButton.html#//apple_ref/occ/instm/UIButton/titleForState:
Try like this:
-(void) clicks:(id)sender
{
if ([sender isKindOfClass:[UIButton class]])
{
UIButton *button = (UIButton*)sender;
NSString *title = button.currentTitle;
// do whatever you want with title
}
}
Try Like,
-(void)clicks:(id)sender{
UIButton *resultebutton= (UIButton*)sender;
label.text=resultebutton.titleLabel.text;
}

How to get instance variable name?

I created a simple iPhone screen with two UIButtons programmatically like below.
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *buttonOne = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buttonOne.frame = CGRectMake(60, 70, 200, 40);
[buttonOne setTitle:#"One" forState:UIControlStateNormal];
[self.view addSubview:buttonOne];
UIButton *buttonTwo = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buttonTwo.frame = CGRectMake(60, 250, 200, 40);
[buttonTwo setTitle:#"Two" forState:UIControlStateNormal];
[self.view addSubview:buttonTwo];
}
Now on press of button with title as "One", I want to get the variable name as "buttonOne", similarly on press of button with title as "Two" I want to get the variable name as "buttonTwo".
I am not finding a way to get the variable name. Any help? Thanks in advance
First off I'd like to disclaim that this is not good coding style. I assume you're doing this because of some special/unique case, or as a proof of concept. In a production app, this is NOT the way to go. You should set your buttons as properties/ivars and you can compare them when they're pressed, or you can assign tags, or separate targets/selectors for each button. Anything you can do to avoid this approach is good because to be honest this approach is kind of terrible (see note at the end of next paragraph about nil/0 values).
You can check out this code below from a previous SO answer - it will return the name of the ivar given the pointer. However, you have to declare your buttons as ivars and not local variables. Also, if two ivars are nil, it will report the same. So this will only work if all your object ivars are not nil, and your primitive type ivars are not 0.
#import <objc/objc.h>
- (NSString *)nameOfIvar:(id)ivarPtr
{
NSString *name = nil;
uint32_t ivarCount;
Ivar *ivars = class_copyIvarList([self class], &ivarCount);
if(ivars)
{
for(uint32_t i=0; i<ivarCount; i++)
{
Ivar ivar = ivars[i];
id pointer = object_getIvar(self, ivar);
if(pointer == ivarPtr)
{
name = [NSString stringWithUTF8String:ivar_getName(ivar)];
break;
}
}
free(ivars);
}
return name;
}
So add a method buttonPressed: as follows:
- (void)buttonPressed:(id)sender {
if ([sender isKindOfClass:[UIButton class]]) {
NSString *buttonName = [self nameOfIvar:sender];
//Now you can do something with your button name
}
}
Source of first block of code: Get property name as a string
we can get only button title name by this way buttonOne.titleLabel.text.
we can't get variable name

Working with big numbers

I have a number like 12345678910111213 and I need to pass it from one method(cellForRow) to another(button action method). The simplest way which I used to use is to pass it through a button tag. In this case it is impossible(?). I can also create a property for it but what about encapsulation? I want to know really RIGHT(and preferably simple) way for doing things like that. Thanks in advance!
Well you can actually attach the value to the UIButton. When you have the value you want to pass and you have a reference to the button:
static char kMyObject;
objc_setAssociatedObject(myButton, &kMyObject, [NSNumber numberWithInt:myInt], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
On the other side, when you receive the action with the button as id:
- (void)myAction:(id)sender
{
UIButton *myButton = (UIButton*)sender;
NSNumber *number=objec_getAssociatedOject(myButton,&kMyObject);
}
You cannot pass it as a tag as Saad said. You can use NSDecimal numbers here.
#Saad cannot use double, as it will lose precision.
In this integer tag you can store a pointer (case of 32 bit address) to a class/structure/whatever what represents bigint.
For example:
UIButton *button = [UIButton ...];
button.tag = (int)[[MyBigInt alloc] initWithString:#"12131312312312312"];
after:
MyBigInt *bigInt = (MyBigInt *)button.tag;
...
[bigInt release];
I'm going to make some assumptions here, because I just when through something similar.
The UIButton with the action is in a UITableViewCell.
You have an underlying source for all your data (ie. An array with all your data in it).
You have easy access to your tableView.
First, you need to get the cell which contains the button:
UITableViewCell *cell = nil;
for (UIView *view = sender; view; view = view.superview) {
if ([view isKindOfClass:[UITableViewCell class]]) {
cell = (UITableViewCell *)view;
break;
}
}
Next, you need to get the indexRow for that cell:
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
Finally, you have to get access to your data:
ModelClass modelObject* obj = [self.data objectAtIndex:indexPath.row];
Now, you can make any changes you need to your model.

UIButton sender title problem

seems like a quite easy problem but I don't get it.
It have two UIButtons, one is titled 'next' the other is titled 'previous'. Both are linked to the same method. All I wanna do is change the variable 'helpStatus'depending on which button is pressed:
if([sender currentTitle] == #"next"){
helpStatus++;
}
if ([sender currentTitle] == #"previous"){
helpStatus--;
}
NSLog(#"%#", [sender currentTitle]);
the logged titels are 'next' and 'previous' just like it should be but it doesn't work and I don't know why.
You need to use isEqualToString otherwise you are just comparing if they are the same object, not if they are equal :)
if([[sender currentTitle] isEqualToString:#"next"]){
helpStatus++;
}
if ([[sender currentTitle] isEqualToString:#"previous"]){
helpStatus--;
}
I would not use the string. What happens if you decide to change the label? Consider using a tag instead.
e.g. b
button.tag = 100;
...
- (void)buttonPressed:(id)sender {
UIButton *button = (UIButton*)sender;
if(button.tag == 100) {
}
}
or in your case (I am kidding, sort of), even:
button1.tag = 1;
button2.tag = -1;
...
- (void)buttonPressed:(id)sender {
UIButton *button = (UIButton*)sender;
helpStatus+= button.tag;

How to assign a value or title to a UIbutton instance so I can access it when I press the button?

I want to create a basic app where you have 8 numbered buttons, with a randomly generated number on each. You are given a total value, and have to click on buttons whose numbers add up to that value.
I need to show which buttons have been 'used' already (I hope to use the selected state for that, as I am using a custom button).
When you press a button, it needs to add the correct value to the 'totalSoFar and change the button to it's selected state.
The plan is that I currently have 8 UIButtons (b1, b2 etc). I have generated a random array of numbers, that I want to assign as the title of the button.
I have tried about a million variations on the theme of [b1 setTitle etc] but can't get it to work.
I have added a textview on top of the button (n1, n2...) that now displays my random numbers instead.
I have got it so that when you press a button, it gets the tag of that button, and then finds the matching position in the array, so I can use that value in the 'what's the total of all the buttons I have pressed' calculation. I cannot however figure out how to access the sender button in order to tell it to change to selected.
I'd much rather do this by just changing the title of the button, rather than having to have an extra textfield.
I am still quite new to Objective C, having previously only coded in actionscript for Flash, and I'm only asking after spending about 4 hours trying to search for a solution online (and swearing at my computer a lot...)
Here's what I have so far... I have tagged each button, so that b1 has a tag of 0, b2 has a tag of 1 etc...
-(IBAction) pressed:(id)sender {
int i;
UIButton *button = (UIButton *)sender;
for (i=0; i<8; i++) {
if ([button tag] == i)
{
//returns value in array as a string
NSString *temp2 = [pnumbers objectAtIndex:i];
//checks string value to see what total to add
if ([temp2 isEqualToString:#"1"]) {
total +=1;
}
if ([temp2 isEqualToString:#"2"]) {
total +=2;
}
if ([temp2 isEqualToString:#"3"]) {
total +=3;
}
if ([temp2 isEqualToString:#"4"]) {
total +=4;
}
if ([temp2 isEqualToString:#"5"]) {
total +=5;
}
if ([temp2 isEqualToString:#"6"]) {
total +=6;
}
if ([temp2 isEqualToString:#"7"]) {
total +=7;
}
if ([temp2 isEqualToString:#"8"]) {
total +=8;
}
if ([temp2 isEqualToString:#"9"]) {
total +=9;
}
}
}
}
I don't want to just make a new function for each separate button (as I plan to have 64 buttons in the end) in order to be able to access which button it was without lots of if and for statements. If nothing else, that seems like bad coding to me!
Hope this all makes sense...
I mostly just want to make the damn thing show the selectedState for the correct button once I've clicked on it. I can live with the textfields!
EDIT - for the record, I've now managed to get it to the selected state, by using
[b1 setSelected:FALSE];
at the start, and then adding
UIButton *button = (UIButton *)sender;
[sender setSelected:TRUE];
before the for loop. Still not sure how to get it to deselect the next time it is clicked though.
It seems like your code could be simplified:
- (IBAction) pressed:(UIButton *)sender {
int buttonIndex = [button tag];
total += [[pnumbers objectAtIndex:buttonIndex] intValue];
}
Many thanks to all who helped!
I finally managed to achieve what I wanted using this beautifully simple bit of code:
-(IBAction) pressed:(id)sender {
UIButton *button = (UIButton *)sender;
if ([sender isSelected] ==FALSE) {
[sender setSelected:TRUE];
int buttonIndex = [button tag];
total += [[pnumbers objectAtIndex:buttonIndex] intValue];
NSLog(#"%i", total);
}
else {
[sender setSelected:FALSE];
int buttonIndex = [button tag];
total -= [[pnumbers objectAtIndex:buttonIndex] intValue];
NSLog(#"%i", total);
}
}
Firstly, you're probably looking for -[UIButton setTitle:forState:], where state is probably going to be UIControlStateNormal. The other thing you might want to use is -[NSString intValue].
This would let you do
total += [temp2 intValue];
rather than your case statement.
First, you should be able to simplify your current code a bit:
- (void)pressed:(id)sender
{
UIButton *button = (UIButton *)sender;
total += [sender tag];
}
Then you can call the button's -setSelected: method to change its state:
- (void)pressed:(id)sender
{
UIButton *button = (UIButton *)sender;
total += [sender tag];
[button setSelected:YES];
}
When you create the buttons, use the following method to set its title:
- (void)setTitle:(NSString *)title forState:(UIControlState)state
If you use UIControlStateNormal as the argument, it will use the title for all three of the button's possible states.