Sparked
Sparked

Reputation: 874

Add action to button programmatically

I am trying to add an action to a button programmatically from within a custom class. However, I keep getting an error when I perform the action. I've read a lot about how to do this but am clearly making a mistake somewhere and can't figure out where.

The button is created in the first instance by dragging it onto the storyboard. I then control drag to the ViewControler.h file to get this:

@property (strong, nonatomic) IBOutlet UIButton *testButtonForClass;

In ViewControler.m, I do this:

- (void)viewDidLoad
{
    [super viewDidLoad];

    testClass *myClass = [[testClass alloc]init];
    myClass.myButton = self.testButtonForClass;
    [myClass assignActionTargets];
}

Below is the custom class Header and Implementation file.

Header File

#import <Foundation/Foundation.h> 

@interface testClass : NSObject

@property (nonatomic, strong) UIButton *myButton;

-(void)assignActionTargets;

@end

Implementation File

#import "testClass.h"

@implementation testClass

-(void)assignActionTargets{    
    [self.myButton addTarget:
    self action:@selector(myButtonInnerTap) 
    forControlEvents:(UIControlEventTouchUpInside)]; 
}

-(void)myButtonInnerTap{
     UIAlertView *a = [[UIAlertView alloc]initWithTitle:nil 
     message:@"testClass says hello" 
     delegate:nil 
     cancelButtonTitle:@"Dismiss" 
     otherButtonTitles:nil, nil];

    [a show];
}

@end

Upvotes: 0

Views: 115

Answers (2)

Mundi
Mundi

Reputation: 80271

First, the double nil for the argument otherButtonTitles is "problematic". Reduce it to one.

Second, make sure the button and the object is properly retained by your calling class.

Finally, make sure via NSLog or breakpoints that the objects in question (custom object, button) are not nil.

Upvotes: 0

Gabriele Petronella
Gabriele Petronella

Reputation: 108169

You create a testClass instance, but you don't keep a reference to, so it gets deallocated at the end of viewDidLoad.

- (void)viewDidLoad {
    [super viewDidLoad];

    TestClass *myClass = [[TestClass alloc] init];
    myClass.myButton = self.testButtonForClass;
    [myClass assignActionTargets];

    // myClass gets deallocated here!
}

When the button is clicked, it tries to access the target you specify, but now that's a dangling pointer to an invalid memory segment, hence leading to a crash.

You have to keep a strong reference to myClass in order to keep it alive by the time the button is clicked. Declaring a strong property is a good way of achieving that.

@property (nonatomic, strong) TestClass *myThingy;

- (void)viewDidLoad {
    [super viewDidLoad];

    self.myThingy = [[testClass alloc] init];
    self.myThingy.myButton = self.testButtonForClass;
    [self.myThingy assignActionTargets];
}

Code style note: Please, use some naming conventions. Class names should be capitalized (I already changed that in the above snippets, since it kills me...) and using myClass for a pointer to an instance of a class is plain disorienting.

Upvotes: 1

Related Questions