UIButton target action not being called - ios

Forgive me if this is trivial, I am still honing my programing skills. I am trying to set this button as a target. Should be easy but I dont know why it's not working! I inserted a NSLog to test and the method is not being called! Thanks for your help.
//ShareView.h
#property (strong,nonatomic) UIButton *cancelBtn;
//ShareView.m
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIImage *shareImage = [UIImage imageNamed:#"shareBox.png"];
[self setFrame:CGRectMake(10, 170, shareImage.size.width, shareImage.size.height)];
self.shareIV = [[UIImageView alloc] initWithImage:shareImage];
self.shareIV.userInteractionEnabled = YES;
[self addSubview:self.shareIV];
[self shareBtnsInit];
[self.shareIV addSubview:self.cancelBtn];
self.userInteractionEnabled = YES;
}
return self;
}
-(void)shareBtnsInit{
UIImage *cancelImg = [UIImage imageNamed:#"cancel27.png"];
self.cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.cancelBtn setImage:cancelImg forState:UIControlStateNormal];
[self.cancelBtn setFrame:CGRectMake(277, 3, cancelImg.size.width, cancelImg.size.height)];
}
//MainViewController.m
-(IBAction)settingsButtonPressed:(id)sender{
self.shareVC = [[ShareView alloc] initWithFrame:CGRectMake(0, 0, 0,0)];
[self.view addSubview: self.shareVC];
[self.shareVC.cancelBtn addTarget:self action:#selector(settingsCancel:) forControlEvents:UIControlEventTouchUpInside];
}
-(IBAction)settingsCancel:(id)sender{
NSLog(#"TEST!!!");
[self.shareVC removeFromSuperview];
}

Based on comments, your settingsButtonPressed: method wasn't being called, so the button you were looking for the action on was never being set up.

Try adding [self.cancelBtn addTarget:self action:#selector(settingsCancel:) forControlEvents:UIControlEventTouchUpInside]; to your shareBtnsInit method.
Here's more information on making UIButtons programatically: How do I create a basic UIButton programmatically?

[self.cancelBtn addTarget:MainViewController action:#selector(settingsCancel:) forControlEvents:UIControlEventTouchUpInside];
In ShareView you have to import class in which you want your event should get triggered.
Here in ShareView you can import MainViewController class and can use it.

Related

UIButton not working inside UITableView(crashes on tap)? Can I get some help for obj-c

SOLUTION: it was stupidly simple, I overlooked the need to declare the method for my button function in this implementation, the fix was simply adding this in the right spot (inside the implementation... duh!)
-(void)bugButton { //do stuff }
Found some code for a button that looked like what I wanted. After adding & compiling the button crashes my app when tapped, any idea why? Heres the entire cell, pretty new to making these so its hacked together from other stuff, the button stuff is near the top. I do have the method in a different place (and have used boring PSButtonCell's successfully so I know that the method works)
#interface harpButtonCell : PSTableCell <PreferencesTableCustomView> {
}
#end
#implementation harpButtonCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(id)reuseIdentifier specifier:(id)specifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier];
if (self) {
// icon
UIImage *bugImage = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:#"%#/Bug.png", kSelfBundlePath]];
UIButton *bugbutton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 75, 75)];
[bugbutton setImage:bugImage forState:UIControlStateNormal];
[bugbutton addTarget:self action:#selector(bugButton) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:bugbutton];
/*
UIImage *paypalImage = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:#"%#/Paypal.png", kSelfBundlePath]];
UIButton *paypalbutton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 75, 75)];
[paypalbutton setImage:paypalImage forState:UIControlStateNormal];
[paypalbutton addTarget:self action:#selector(paypalButton) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:paypalbutton];*/
//int width = self.contentView.bounds.size.width;
}
return self;
}
- (instancetype)initWithSpecifier:(PSSpecifier *)specifier {
return [self initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"harpButtonCell" specifier:specifier];
}
- (void)setFrame:(CGRect)frame {
frame.origin.x = 0;
[super setFrame:frame];
}
- (CGFloat)preferredHeightForWidth:(CGFloat)arg1{
return 100.0f;
}
- (CGFloat)preferredHeightForWidth:(CGFloat)width inTableView:(id)tableView {
return [self preferredHeightForWidth:width];
}
#end
It seems that you don't implement the action of button, try to add the action in the cell:
-(void)bugButton{
NSLog(#"you clicked on button");
}

How to invoke a method from UIViewController class to Custom UIView class

I am not able to call the method which is written in UIViewController(aViewController) from my custom view bView .
I want to call the method function on my button(btn) click in UIView(bView). But when I click the button, i am getting the following error.
unrecognized selector sent to instance....
Here is my code:
aViewController.h
#import "bView.h"
#import "cViewController.h"
-(void)function;
aViewController.m
-(void)viewDidLoad{
bView = [[bView alloc]init];
[bView makeView];
bView.bViewController = self;
[self.view addSubView:bView];
}
-(void)function{
cViewController *nextViewController = [[cViewController alloc] initWithNibName: nil bundle: nil];
[self.navigationController pushViewController: nextViewController animated: YES];
}
bView.h
#import "bViewController.h"
#interface bView : UIView{
UIButton btn;
bView *BView;
}
-(void)makeView;
-(void)function;
#property (nonatomic,readonly) UIButton *btn;
#property (assign) UIViewController* aViewController;
bView.m
#import "bView.h"
#import "aViewController.h"
#impementation bView
#synthesize btn;
#synthesize aViewController;
-(void)makeView{
btn= [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIImage *btnimg = [UIImage imageNamed:#"btn.png"];
[btn setBackgroundImage:btnimg forState:UIControlStateNormal];
btn.frame = CGRectMake(65, 380, 60, 60);
[self addSubview:btn];
btn.userInteractionEnabled = YES;
[btn addTarget:aViewController action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
}
How to solve it?
You are setting a target to button in [bView makeView]; method, but at that time bView's aViewController is nil because you are setting it only on the next line. So try this:
-(void)viewDidLoad{
bView = [[bView alloc]init];
bView.bViewController = self;
[bView makeView];
[self.view addSubView:bView];
}
this is how you do it, first off, get rid of the "bView.bViewController = self", it doesn't work that way, you shouldn't do this, ever.
-(void)viewDidLoad {
bView = [[bView alloc]init];
[bView makeView];
[self.view addSubView:bView];
[[bView btn] addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
}
function is declared in your UIViewController, not your UIView, so you must call to the button in your viewdidLoad through the bView and then assign it a target and action. I still wouldn't use this method that you are using, but this will do it.
this is the magic:
[[bView btn] addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
AND, remove these lines from the UIView:
#property (assign) UIViewController* aViewController;
-(void)function;
[btn addTarget:aViewController action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
you should remove these if your intent is for the UIViewController to have the function "-(void)function" and I assume this is what you meant. I'm assuming that your "function" is supposed to be called in your UIViewController
for out purposes here, this:
[[bView btn] addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
is the same thing as this:
[bView.btn addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
and
bView.btn = #property (nonatomic,readonly) UIButton *btn;
In fact, you don't need to call this button in any UIView, given what you are showing, just call this in your viewDidLoad, like this:
-(void)viewDidLoad
{
[super viewDidLoad];
UIButton * btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
UIImage *btnimg = [UIImage imageNamed:#"btn.png"];
[btn setBackgroundImage:btnimg forState:UIControlStateNormal];
btn.frame = CGRectMake(65, 380, 60, 60);
btn.userInteractionEnabled = YES;
[self.view addSubview:btn];
[btn addTarget:self action:#selector(function) forControlEvents:UIControlEventTouchUpInside];
}
I'm showing you this because you aren't setting up the UIView correctly in the first place by invoking super on it's designated initializer so the best bet now is to just place the button in your viewDidLoad and move on, this is the solution until you understand how the initialize a UIView and set it up correctly. There's a lot of stuff that is wrong with the UIView you have set up and tried to subclass and it's going to be easier for you to just make the button in viewDidLoad and then learn how to subclass correctly in the future.

inputaccessoryview not showing (StoryBoard)

I have been trying to incorporate a UIView/Toolbar above my keyboard but have had no luck. When I added a toolbar it was scrambled so thus I need to put it into a UIView but the UIView does not want to appear above the keyboard. Code Below:
My Header:
#property (nonatomic, Strong) IBOutlet UITextView *textView;
#property (nonatomic, strong) IBOutlet UIToolbar *TitleBar;
#property (nonatomic, weak) IBOutlet UIView *AddView;
The ViewDidLoad:
- (void)viewDidLoad
{
// observe keyboard hide and show notifications to resize the text view appropriately
/*[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
*/
if ([self respondsToSelector:#selector(setNeedsStatusBarAppearanceUpdate)]) {
// iOS 7
[self performSelector:#selector(setNeedsStatusBarAppearanceUpdate)];
} else {
// iOS 6
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
}
self.attributionTitle.delegate = self;
self.attribution.delegate = self;
textView.scrollEnabled = YES;
// quoteText.layer.borderColor = [UIColor blackColor].CGColor;
// quoteText.layer.borderWidth = 1.0f;
// textView.delegate = self; // code or in IB
[textView becomeFirstResponder];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
The textViewDidBeginEditing:
-(void)textViewDidBeginEditing:(UITextView *)textView
{
self.textView.inputAccessoryView = self.AddView;
}
Here is to show the UIView is connected:
I added the textView.inputAccessoryView = AddView;to the ViewDidLoadthen deleted the view from my storyboard and remade it. Lastly I added the UIView to the bottom black bar.
Adding the inputAccessoryView in textViewDidBeginEditing is probably too late. The input accessory view should be set before that, e.g., in the viewDidLoad method.
Try something like:
-(void)viewDidLoad{
[super viewDidLoad];
UIView
myTextField.inputAccessoryView = [self accessoryViewWithPreviousEnabled:NO nextEnabled:YES];
// more stuff as required...
}
And a method for creating a previous/next button (you'll need to provide your own images for the buttons and implements the previousAccessoryViewButtonTapped: and previousAccessoryViewButtonTapped: methods). It takes two BOOL parameters to indicate if the previous and/or next buttons should be enabled.
#pragma mark - Accessory view methods
-(UIView *)accessoryViewWithPreviousEnabled:(BOOL)previousEnabled nextEnabled:(BOOL)nextEnabled{
previousButton = [UIButton buttonWithType:UIButtonTypeCustom];
previousButton.frame = CGRectMake(10, 2, 60, 30);
[previousButton setImage:[UIImage imageNamed:PREVIOUS_BUTTON] forState:UIControlStateNormal];
previousButton.enabled = previousEnabled;
[previousButton addTarget:self action:#selector(previousAccessoryViewButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
nextButton = [UIButton buttonWithType:UIButtonTypeCustom];
nextButton.frame = CGRectMake(80, 2, 60, 30);
[nextButton setImage:[UIImage imageNamed:NEXT_BUTTON] forState:UIControlStateNormal];
nextButton.enabled = nextEnabled;
[nextButton addTarget:self action:#selector(nextAccessoryViewButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
UIView *transparentBlackView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024, 34)];
transparentBlackView.backgroundColor = [UIColor colorWithRed:0.f green:0.f blue:0.f alpha:0.6f];
UIView *accessoryView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1024, 34)];
[accessoryView addSubview:transparentBlackView];
[accessoryView addSubview:previousButton];
[accessoryView addSubview:nextButton];
return accessoryView;
}
Note this method is hard coded for an iPad in landscape orientation. You need to change it for an iPhone.
The problem is that your self.AddView is already in your interface (because you put it there, in the storyboard). It can't be in two places at once.

Create a custom UIButton class with delete function

I have a grid of UIButtons. When I hit an 'edit' button, I want a delete button to appear over each of these buttons, which when pressed, deletes the button (and associated data). A bit like apple's home screen, when you hold down a button and it starts to wiggle with an X in the corner.
According to this post: Subclass UIButton to add a property I can use Associative References to add a property to each of my buttons. I've tried to add a UIButton as a property of my custom UIButton but I can't seem to get it to appear and have the feeling this isn't the right way to go. Here's my custom button main:
#import "UIButton+Property.h"
#import <objc/runtime.h>
#implementation UIButton(Property)
static char UIB_DELETEBUTTON_KEY;
#dynamic deleteButton;
- (void)setDeleteButton:(UIButton *)deleteButton {
deleteButton = [UIButton buttonWithType:UIButtonTypeInfoDark];
deleteButton.frame = CGRectMake(100, 100, 50, 50);
objc_setAssociatedObject(self, &UIB_DELETEBUTTON_KEY, deleteButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIButton *)deleteButton {
return (UIButton *)objc_getAssociatedObject(self, &UIB_DELETEBUTTON_KEY);
}
#end
And here's where I add the buttons programmatically:
//Create a custom button for each custom book doc
for (int i = 0; i < [customBookDocs count]; ++i) {
BookDoc *customBookDoc = [customBookDocs objectAtIndex:i];
NSString *bookTitle = customBookDoc.book.title;
//create a button for each book
CGRect frame = CGRectMake(xCoord, yCoord, 200, 200);
UIButton *bookButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
bookButton.bookDoc = customBookDoc;
[bookButton setFrame:frame];
[bookButton setTitle:bookTitle forState:UIControlStateNormal];
[bookButton addTarget:self action:#selector(bookButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
xCoord += 250;
[self.view addSubview:bookButton];
[self.view addSubview:bookButton.deleteButton];
}
Is there an easier more sensible way to do this? Or am I on the right track?
ORIGINAL RESPONSE BEGAN:
... Someone else may have more to say about that, but I'm not sure why you'd need to use object association here. You can certainly add another button to your button as a property using regular subclassing, which is the route that I would take. ...
EDITS BELOW:
I thought that I had subclassed a UI control directly, but I realized that I was mistaken when I went to look for the code. #Joe rightly pointed out in the comments that there are issues with directly subclassing UI controls.
I was able to implement something like the functionality you described without using Associated Objects, by creating a wrapper class to hold the button and its related delete button. It works, but it's not very flexible, so I would generally recommend #Joe's method as a better solution.
Here's the relevant code:
I threw all of the code into the appDelegate to keep it simple. I don't recommend that in real life.
AppDelegate.m:
#implementation AppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
UIButton *toggleDeleteButtons = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[toggleDeleteButtons setFrame:CGRectMake(20, 45, 280, 45)];
[toggleDeleteButtons setTitle:#"Toggle Delete" forState:UIControlStateNormal];
[toggleDeleteButtons addTarget:self action:#selector(toggleDeleteButtonAction) forControlEvents:UIControlEventTouchUpInside];
[[self window] addSubview:toggleDeleteButtons];
ButtonWrapper *myButtonWrapper = [[ButtonWrapper alloc] init];
[[myButtonWrapper button] setFrame:CGRectMake(20, 100, 200, 45)];
[[myButtonWrapper button] setTitle:#"This is my button" forState:UIControlStateNormal];
[[myButtonWrapper deleteButton] addTarget:self action:#selector(buttonDeleteRequested:) forControlEvents:UIControlEventTouchUpInside];
[[myButtonWrapper deleteButton] setTag:0];
[[self window] addSubview:[myButtonWrapper button]];
buttonWrapper1 = myButtonWrapper;
// Added instance called anotherButtonWrapper with tag 1, as above
// Added instance called stillAnotherButtonWrapper with tag 2, as above
[self.window makeKeyAndVisible];
return YES;
}
- (void)toggleDeleteButtonAction {
static BOOL deleteButtonsShown;
[buttonWrapper1 showDeleteButton:!deleteButtonsShown];
[buttonWrapper2 showDeleteButton:!deleteButtonsShown];
[buttonWrapper3 showDeleteButton:!deleteButtonsShown];
deleteButtonsShown = !deleteButtonsShown;
}
- (void)buttonDeleteRequested:(UIButton *)deleteButton {
// delete the specified button here
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Delete" message:[NSString stringWithFormat:#"Delete was pressed on button %i",[deleteButton tag]]delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
ButtonWrapper.m:
#implementation ButtonWrapper
#synthesize button;
#synthesize deleteButton;
- (ButtonWrapper *)init {
ButtonWrapper *newWrapper = [ButtonWrapper alloc];
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[myButton setFrame:CGRectZero];
UIButton *myDeleteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[myDeleteButton setFrame:CGRectMake(0, 0, 100, 40)];
[myDeleteButton setTitle:#"Delete" forState:UIControlStateNormal];
[myDeleteButton setHidden:TRUE];
[myButton addSubview:myDeleteButton];
[newWrapper setButton:myButton];
[newWrapper setDeleteButton:myDeleteButton];
return newWrapper;
}
- (void)showDeleteButton:(BOOL)showButton {
if (showButton) {
[[self deleteButton] setHidden:FALSE];
[[self deleteButton] setEnabled:TRUE]; }
else {
[[self deleteButton] setHidden:TRUE];
[[self deleteButton] setEnabled:FALSE];
}
}
#end
This solution did not require me to implement all of the UI properties, but it did require extra work to hook up the embedded delegates, which is cumbersome. There may be a way to pass the delegates into the wrapper at initialization, but I couldn't make it work.

UIButton addTarget does not in invoke selector

Let me first state, that this is not a matter of getting my selector name right, nor setting up the button target in loadView, nor any other suggestion I've seen in the last 4 hours of browsing. I should also explain I am not using nibs, nor IB.
These buttons have been working for the bulk of development.
Then poof! It's not just the buttons. My table views do not scroll. Pressing the cells in the table views do not invoke the actions that I had setup.
It seems I've broken the responder chain entirely; or something to that effect.
To try and narrow down the source of the problem a created a window-based project; stripped out everything that xCode generates; deleted the nib; and copied in several methods from my original app delegate and my rootViewController.
It's the RVT that contains the subView that contains the buttons. Fairly straight forward. Same effect. I've literally stripped out all functional code but the following source in appDelegate.m:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setDelegate:self];
if(window == nil)
window = [[UIWindow alloc] init];
window.autoresizesSubviews = YES;
if(controller == nil)
controller = [[Controller alloc] init];
window.rootViewController = controller;
[window makeKeyAndVisible];
return YES;
}
-(void)dealloc {
[window release];
[controller release];
[super dealloc];
}
And in Controller:
- (void)buttonResponse {
NSLog(#"Button touched up inside!!!!!");
}
- (void)loadView {
[super loadView];
//test
button = [UIButton buttonWithType:UIButtonTypeCustom];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Button" ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
CGSize imageSize = [image size];
CGRect buttonFrame = CGRectMake(0,0,imageSize.width + 100, BUTTONBAR_H + 100);
button.frame = buttonFrame;
[button setImage:image forState:UIControlStateNormal];
button.backgroundColor = [UIColor blueColor];
[button setTitle:#"" forState:UIControlStateNormal];
button.userInteractionEnabled = YES;
[button addTarget:self action:#selector(buttonResponse) forControlEvents: UIControlEventTouchUpInside];
UIView *view = self.view;
CGRect viewFrame = view.frame; //self.view is valid and takes up available screen
[self.view addSubview:button];
[self.view bringSubviewToFront:button];
//end test
[self.view setNeedsDisplay];
}
- (void)dealloc {
[button release];
[super dealloc];
}
I know it's gotta be something really simple. But I can't see it. I would prefer to leave my hair in place. I'm wondering if that's going to happen as I continue to learn the quirks.
Does loadView ever get called? Put a NSLog (or a breakpoint) in loadView just as a sanity check.
Also, from UIViewController Documentation:
If you override this method (loadView) in order to create your views manually,
you should do so and assign the root view of your hierarchy to the
view property. (The views you create should be unique
instances and should not be shared with any other view controller
object.) Your custom implementation of this method should not call super.
If you want to perform any additional initialization of your views, do
so in the viewDidLoad method. In iOS 3.0 and later, you
should also override the viewDidUnload method to release any
references to the view or its contents.
Try putting all the button code in viewDidLoad:
- (void)buttonResponse:(id)sender {
NSLog(#"Button touched up inside!!!!!");
}
- (void)loadView {
// Dont call super (according to the UIViewController docs)
// [super loadView];
// self.view = ... however your setting up self.view
// self.view.frame = CGRectMake....
// self.view.etc...
[self.view setNeedsDisplay];
}
- (void)viewDidLoad {
[super viewDidLoad];
button = [UIButton buttonWithType:UIButtonTypeCustom];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Button" ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
CGSize imageSize = [image size];
CGRect buttonFrame = CGRectMake(0,0,imageSize.width + 100, BUTTONBAR_H + 100);
button.frame = buttonFrame;
[button setImage:image forState:UIControlStateNormal];
button.backgroundColor = [UIColor blueColor];
[button setTitle:#"" forState:UIControlStateNormal];
button.userInteractionEnabled = YES;
[button addTarget:self action:#selector(buttonResponse:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
[self.view bringSubviewToFront:button];
}
- (void)dealloc {
[button release];
[super dealloc];
}

Resources