I have a custom UIButton class like below :
.h
#import <UIKit/UIKit.h>
#class FriendButton;
#protocol LongPressedButtonDelegate
- (void)buttonIsLongPressed:(FriendButton *)button;
#end
#interface FriendButton : UIButton
#property (nonatomic, weak) id<LongPressedButtonDelegate > delegate;
#end
.m
#implementation FriendButton
//this is called from the interface builder
-(id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:(NSCoder *)aDecoder];
NSLog(#"init called");
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(longPress:)];
[self addGestureRecognizer:longPress];
return self;
}
-(void)longPress:(id)sender {
NSLog(#"long press");
[self.delegate buttonIsLongPressed:self];
}
#end
My buttons are set up in the interface builder, they are contained in a UITableView cell. In my UITableViewController I have :
-(void)buttonIsLongPressed:(FriendButton *)button {
NSLog(#"Delegate method!");
}
and it controller conforms to protocol. The long press gesture works but the delegate method is not being called. I'm not sure why it's not working. Is it because I have to set each buttons delegate to the UITableViewController? If so how would I do that? The buttons are set up in the interface builder.
Define your UIButton property this way
#interface FriendButton : UIButton
#property (nonatomic, weak) IBOutlet id<LongPressedButtonDelegate > delegate;
#end
Then go to Interface Builder and right click on UIButton and you will see delegate link this delegate to UITableViewController. It should work
In your cellForRowAtIndexPath implementation in your UITableViewController you will need to do something like:
cell.button.delegate = self;
Edit: This is if you want to do it programmatically. Refer to the answers around IBOutlets if you want to do it in your storyboard.
Related
I have a custom class called NumberView which subclasses UIScrollView. I put a UIView onto my storyboard and changed the class to NumberView:
I then created an outlet to my ShotTraceViewController class:
#interface ShotTraceViewController ()
#property (weak, nonatomic) IBOutlet NumberView *numberView;
#end
I've defined a few methods in the NumberView.h and NumberView.m:
.h:
#interface NumberView : UIScrollView
#property (weak, nonatomic) id<NumberViewDelegate> number_delegate;
-(void)setTotalBtns:(int)total;
...
#end
.m:
#interface NumberView ()
#end
#implementation NumberView {
}
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
return self;
}
-(void)setTotalBtns:(int)total {
NSLog(#"Setting buttons");
}
#end
But when I try to call [self.numberView setTotalBtns:3]; from my ShotTraceViewController. I get an exception:
-[UIView setTotalBtns:]: unrecognized selector sent to instance 0x104fad3e0
Whoa! That's not right, it's supposed to be a NumberView not a UIView! Am I doing something wrong?
I've also noticed that initWithFrame and initWithCoder are both not being called.
I don't know why this worked, but unchecking the Inherit Module from Target button underneath the class selection fixed everything.
I have UIView, what called Popup and poping from UIViewContorller(ParentVC)
On UIView I have 4 buttons. When buttons is pressed, it needs to open new Controllers from(ParentVC). I am using Delegate, were is my mistake?
//Popup.h
#protocol PopupDelegate
#required
- (IBAction)stepOfRestoration:(id)sender;
- (IBAction)clientCall:(id)sender;
- (IBAction)readyTo:(id)sender;
- (IBAction)givePhone:(id)sender;
#end
#interface Popup : PSCustomViewFromXib
#property (nonatomic, assign) id <PopupDelegate> delegate;
#property (strong, nonatomic) IBOutlet UIView *view;
- (IBAction)stepOfRestoration:(id)sender;
- (IBAction)clientCall:(id)sender;
- (IBAction)readyTo:(id)sender;
- (IBAction)givePhone:(id)sender;
In .m i have this:
#synthesize delegate;
....
- (IBAction)stepOfRestoration:(id)sender {
[self.delegate buttonPressed];
}
And this is Parent .m
...
CGRect rect = CGRectMake(0,0,200,300);
Popup *popup1 = [[Popup alloc] initWithFrame:rect];
popup1.delegate = self;
....
-(void)buttonPressed {
[self performSegueWithIdentifier:#"infoSegue" sender:nil];
}
So were is my mistake?
You don't have a method called buttonPressed in your protocol, you need to call a method in your protocol, e.g.
Popup.m
- (IBAction)buttonPressed:(id)sender {
[self.delegate stepOfRestoration:sender];
}
Parent.m
- (IBAction)stepOfRestoration:(id)sender {
// some code
}
Link to long winded but hopefully helpful tutorial, good luck.
In your Parent .m, you must conform all the methods which are defined in protocol. In your Parent.m file, buttonPressed method is not present in protocol. So update the name of below method with buttonPressed as follow:-
Update below code at Popup.h while declaring PopupDelegate methods
- (IBAction)stepOfRestoration:(id)sender;
With
-(void)buttonPressed;
you shouldn't add IBAction methods in your protocol
instead add following methods corresponding each button action
//Popup.h
#protocol PopupDelegate
#required
- (Void)stepOfRestoration:(id)sender;
- (Void)clientCall:(id)sender;
- (Void)readyTo:(id)sender;
- (Void)givePhone:(id)sender;
#end
and call these protocol methods in corresponding button action methods
e.g. //Popup.m
- (IBAction)stepOfRestoration:(id)sender {
[self.delegate stepOfRestoration:sender];
}
and //Parent.m
-(Void)stepOfRestoration:(id)sender{
// code here
}
I created a custom UIView with the buttons above , this view opens as a pop- up to a viewcontroller . I want the view controller intercepts the pressure of the buttons so I created a protocol methods but delegates in the view controller is never called.
The protocol:
#protocol InsertDelegate <NSObject>
-(void)addNode:(double)x pointY:(double)y radius:(double)r forw:(int)forw;
-(void)cancelView:(UIView*)view;
#end
In the AddNewNode.h
#interface AddNewNode : UIView
#property (assign, nonatomic)id <InsertDelegate> delegate;
- (IBAction)actionCancel:(id)sender;
- (IBAction)actionAdd:(id)sender;
#end
In the AddNewNode.m
- (IBAction)actionCancel:(id)sender { //this action is connect with storyboard
NSLog(#"%#", self.delegate);
//(null)
[self.delegate cancelView:self];
}
- (IBAction)actionAdd:(id)sender { //this action is connect with storyboard
NSLog(#"%#", self.delegate);
//(null)
[self.delegate addNode:x pointY:y radius:r forw:f];
}
In ViewController.h:
#interface ViewController : UIViewController <InsertDelegate>
In ViewController.m
(IBAction)addNewNode:(id)sender {
AddNewNode * addRowView =[[AddNewNode alloc]init];
addRowView.delegate=self;
[self.view addSubview: addRowView];
}
//delegate methods never called
-(void)addNode:(double)x pointY:(double)y radius:(double)r forw:(int)forw{
}
-(void)cancelView:(UIView*)view{
}
In UIView custom self.delegate become null and I don't understand why
What about making an IBOutlet for your
ViewController.h
#interface ViewController : UIViewController <InsertDelegate>
#property (strong, nonatomic) AddNewNode * addNewNode;
//or connect IBOutlet of your `addNewNode`
#property (strong, nonatomic) IBOutlet (addNewNode);
#end
ViewController.m
- (IBAction)addNewNode:(id)sender
{
// you dont need to allocate anymore
self.addRowView.delegate=self;
// and you need to trigger the delegate from `- (IBAction)actionAdd:(id)sender;`
[self.addRowView actionAdd:sender];
}
try the following
Create a private property to hold the instance
#implement AddNewNode()
#propery (nonatomic, strong) AddNewNode * addNewNode;
#end
from inside the button handler
(IBAction)addNewNode:(id)sender {
self.addNewNode =[[AddNewNode alloc]init];
self.addRowView.delegate=self;
}
I have a custom view that uses a gesture recognizer that calls a method handleSingleTap. This works fine if the setup for the gesture recognizer and the selector it calls are in the same custom view (CircleView).However, I need the handleSingleTap method in the viewController, so I (1) created a protocol in the custom view (CircleView), (2) created the delegate property in the view, and when I (3)created the gesture recognizer, I set self.delegate for the target of handleSingleTap (rather than just self as it was initially). In the viewController.h, (4) I said that it conformed to the protocol and declared the method handleSingleTap. In the .m file of the view controller, I created a property for the custom view (CircleView) and then in viewDidLoad of the .m file, set self to be the delegate of the custom view. However, the handleSingleTap method is never getting called in the viewController when I tap on the circle in the custom view.
Can you explain why the selector handleSingleTap is not getting called in the viewController?
1) created protocol
#protocol CircleViewDelegate <NSObject>
-(void)handleSingleTap:(UITapGestureRecognizer *) tapper;
#end
2) created delegate property
#property (nonatomic, weak) id <CircleViewDelegate> delegate;
in CircleView
3) created gesture recognizer with target self.delegate
-(void)setUpGestureRecognizers{
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self.delegate action:#selector(handleSingleTap:)];
singleFingerTap.numberOfTapsRequired=1;
[self addGestureRecognizer:singleFingerTap];
}
4) in the viewController.h,
#interface ViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate, CircleViewDelegate>
-(void)handleSingleTap:(UITapGestureRecognizer *) tapper;
in the viewController.m
#property (strong, nonatomic) CircleView *overlay;
viewDidLoad
self.overlay.delegate = self;
This method in the viewController is not getting called
-(void)handleSingleTap:(UITapGestureRecognizer *) tapper {
NSLog(#"never getting called");
}
This is one solution for you. Of course you can do it with Selectors too, but this will work for sure too.
.h
#import <UIKit/UIKit.h>
#protocol CircleViewDelegate <NSObject>
#required
- (void) circleViewPressedByOneTap;
#end
#interface CircleView : UIView
#property (nonatomic,assign) id<CircleViewDelegate> delegate;
- (id)initWithFrame:(CGRect)frame andWithDelegate:(id<CircleViewDelegate>)del;
#end
.m:
#import "CircleView.h"
#interface CircleView () <UIGestureRecognizerDelegate>
#end
#implementation CircleView
#synthesize delegate;
- (id)initWithFrame:(CGRect)frame andWithDelegate:(id<CircleViewDelegate>)del
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
delegate = del;
[self setUpGestureRecognizers];
}
return self;
}
-(void)setUpGestureRecognizers{
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleFingerTap.numberOfTapsRequired=1;
[self addGestureRecognizer:singleFingerTap];
}
-(void)handleSingleTap:(UITapGestureRecognizer *) tapper{
[delegate circleViewPressedByOneTap];
}
And in your ViewController .m:
#import "YouClassViewController.h"
#import "CircleView.h"
#interface YouClassViewController () <CircleViewDelegate>
#end
#implementation YouClassViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
CircleView* yourCircleView = [[CircleView alloc] initWithFrame:CGRectMake(0, 0, 50, 50) andWithDelegate:self];
[self.view addSubview:yourCircleView];
}
- (void) circleViewPressedByOneTap{
NSLog(#"Yeaah you pressed it ! :) ");
}
In file .h I have:
#protocol VVInformationTableViewControllerDelegate;
#interface VVInformationTableViewController : UITableViewController <UITextFieldDelegate, UIGestureRecognizerDelegate, UIPickerViewDataSource, UIPickerViewDelegate, UITableViewDelegate>
#property (strong, nonatomic) VVUser* currentAttendee;
#property (weak, nonatomic) id<VVInformationTableViewControllerDelegate> delegate;
In file .m:
In viewDidLoad:
self.tableView.delegate = self;
and I have method:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
[self dismissKeyboard];
NSLog(#"HEJ");
}
But when I dragging my tableView (no matter if keyboard is show or not) this method didn't work. I looked for this problem but I couldn't find asnwer.
EDIT:
I make this (scrollViewWillBeginDragging) method in parentViewController and it works. But when I call in this method in parentViewController [self.infoTableView dismissKeyboard] (VVInformationTableViewController as childViewController) which is in childView It didn't work. For example if I try use dismissKeyboard:
- (void)dismissKeyboard {
[self.textField resignFirstResponder];
NSLog(#"%#", self.textField.text);
}
in childView then self.textField.text in NSLog is good, but when I try call it in parentView then it is nil, so resignFirstResponder on this textfield didn't work.
I make protocol with method dismissKeyboard in .h of childViewController and:
-(void)textFieldDidBeginEditing:(UITextField *)textField{
self.textField = textField;
self.tableView.scrollEnabled = NO;
}