I have a UIView .xib file. This is opened from the storyboard entry point UIViewController1 as a subview. The subview has a IBButton which when pressed opens a UIViewController2. Is this possible by any chance?
First, create a segue going from your first view controller to your second. I'm going to name it OpenViewController2. We'll be able to call that segue programmatically.
In your UIView .h file, create a protocol that defines a delegate for that view:
SomethingView.h:
#protocol SomethingViewDelegate <NSObject> {
- (void)importantThingHappened;
}
...
#interface SomethingView {
id<SomethingViewDelegate> delegate;
}
#property (nonatomic, strong) id<SomethingViewDelegate> delegate;
SomethingView.m:
#implementation
#synthesize delegate;
...
// The IBAction for the button in your view
- (IBAction)buttonClicked:(id)sender {
[delegate importantThingHappened];
}
MyViewController.m, where you create your view:
// Create view
UIView *myView = ...
myView.delegate = self;
Later in MyViewController:
// Implement the protocol. This function will be called when the button action
// inside of the UIView you created is pressed
- (void)importantThingHappened {
[self performSegueWithIdentifier:#"OpenViewController2" sender:self];
}
First give your IBButton an unique tag, and in your UIViewController's viewDidLoad,
// add following line into viewDidLoad
[(UIButton*)[self.view viewWithTag:MY_UNIQUE_TAG_FOR_BUTTON] addTarget:self action:#selector(buttonPressed:) forControlEvent:UIControlEventTouchUpInside];
and finally implement the buttonPressed: for whatever you want
-(void) buttonPressed:(UIButton*)aButton {
// do what you want to do.
}
Related
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 have created a view with a XIB (MyXIB) and created a UIView Subclass (MyViewSubclass). I set the MyViewSubclass as the "Custom Class" for the MyXIB's View.
I have connected a button in MyXIB to an IBAction in MyViewSubclass.
In the main View Controller of the app, I call:
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:#"MyXIB" owner:self options:nil];
MyUIViewSubclass *myView = [subviewArray objectAtIndex:0];
[self.view addSubview:myView];
This works to add the new view on top of the existing View Controller, but whenever I tap the button from MyXIB, the app crashes and says that it is sending an unrecognized selector to the Parent View Controller.
How can I get the button on MyXIB to invoke the IBAction in MyViewSubclass ?
If you are going to use the view in other view controllers, you should create a delegate protocol, as following:
MyXIB.h
#import <UIKit/UIKit.h>
#protocol MyXIBDelegate <NSObject>
#required // if it's not necessary, you can use #optional
- (void)myXIBDelegateMethod;
#end
#interface MyXIB : UIView
#property (weak, nonatomic) id<MyXIBDelegate> delegate;
#end
MyXIB.m
#import "MyXIB.h"
#implementation MyXIB
- (IBAction)buttonAction:(id)sender {
if (self.delegate && [self.delegate respondsToSelector:#selector(myXIBDelegateMethod)]) {
[self.delegate myXIBDelegateMethod];
}
}
#end
As your UIButton's action is linked in MyXIB view, when the button is pressed, you check if the delegate property is set and if it responds to you delegate method and then you call your protocol's method.
In your view controller .m file at the #implementation section, you would have something like the following:
#import "ViewController.h"
#import "MyXIB.h"
#interface ViewController () <MyXIBDelegate>
#end
And as the protocol method is #required, you have to implement the method in the view controller:
#pragma mark - MyXIB Delegate Method
- (void)myXIBDelegateMethod {
// your implementation
}
I added a custom UIView to a UIViewController and after some code in the view, I want to remove this view from the UIViewController, but I am not sure how to notify the UIViewController of the UIView's removal.
I am using this method to exit from within the UIView
-(void)exit{
[self removeFromSuperview];
}
Do I need to set a listener? Any help is appreciated
I posted a detailed solution. Thanks Rage, Bill L, and FreeNickname
Since it is not convenient to write a code as a comment, I'll write it as an answer. This answer illustrates what #Rage suggested in his answer.
First, you create a #protocol for your CustomView and add a delegate for it. You declare that the delegate should conform to this protocol. Then in your ViewController you implement your protocol and set ViewController as a delegate of your CustomView.
Like so:
CustomView.h:
#protocol CustomViewDelegate<NSObject>
//You can also declare it as #optional. In this case your delegate can
//ignore this method. And when you call it, you have to check, whether
//your delegate implements it or not.
-(void)viewWasRemoved:(UIView *)view
#end
#interface CustomView: UIView
#property (nonatomic, weak) id<CustomViewDelegate> delegate;
#end
CustomView.m:
#implementation CustomView
-(void)exit {
[self removeFromSuperview];
//if your method is NOT #optional:
[self.delegate viewWasRemoved:self];
//if it IS #optional:
if ([self.delegate respondsToSelector:#selector(viewWasRemoved:)]) {
[self.delegate viewWasRemoved:self];
}
}
#end
ViewController.m:
#import "CustomView.h"
#interface ViewController()<CustomViewDelegate>
#end
#implementation ViewController
-(void)someMethod {
self.customView.delegate = self;
}
-(void)viewWasRemoved:(UIView *)view {
//Whatever
}
#end
Use delegation. Add a protocol to your custom View which implements a method to notify the removal of the subview.
Make the View controller the delegate while adding the custom view. In your custom class call the delegate method right before [self removeFromSuperview];
Set up a delegate for it, with a method called viewWasRemoved: or something similar. Set your view's delegate to be the ViewController you want to notify, and then in your exit method, call [self.delegate viewWasRemoved:self];, which will then kick off the viewWasRemoved: method in your ViewController, where you can do any relevant work you need to do once the view is removed.
I'll post a detailed solution in case it helps anyone out, or if anyone can offer any pointers. Thanks Rage, Bill L, and FreeNickname:
The answer is to use delegation
First I imported the superview to the .h of my subview:
#import "ViewController.h"
Then I add a delegate id to the same file:
#property (weak) id delegate;
Then when initializing the custom UIView in the superview, I set the delegate:
CustomView *view = [[CustomView alloc]initWithFrame:frame];
view.delegate = self;
I add this method in the superview for a callback:
- (void) viewWasRemoved: (UIView *) view{
NSLog(#"removed");
}
Then finally call the method in my subView:
-(void)exit{
[self.delegate viewWasRemoved:self];
[self removeFromSuperview];
}
I have a view controller that has a subview that uses a custom class. When I perform performSegueWithIdentifier from the context of the view controller, it works fine, however, how can I call performSegueWithIdentifier from within the context of child subview?
You can't call performSegue from an UIView. You can use a protocol, make the viewController implement it and set it as delegate for your custom view.
CustomView.h
#protocol CustomViewDelegate
-(void)customView:(CustomView *)view performSegueWithIdentifier:(NSString *)identifier;
#end
#property (nonatomic, weak) id<CustomViewDelegate> delegate;
CustomView.m
// This is the event on which you would like to perform the segue
-(void)didClickButton {
[self.delegate customView:self performSegueWithIdentifier:#"mySegue"];
}
ViewController.m
-(void)viewDidLoad {
// All you other stuff...
// Set the delegate
self.customView.delegate = self;
}
-(void)customView:(CustomView *)view performSegueWithIdentifier:(NSString *)identifier {
[self performSegueWithIdentifier:identifier];
}
Hope this helps. Let me know if you have questions
i'm trying to create my first delegate here's what i'm trying to do
at class called PAStepper.h i did this
#class PAStepper;
#protocol StepperDelegate <NSObject>
#required
-(void)didIncrement;
-(void)didDecrement;
#end
#interface PAStepper : UIControl
{
__weak id <StepperDelegate> stepperDelegate;
}
#property (nonatomic, weak) id <StepperDelegate> stepperDelegate;
#end
and synthized the property of course in the .m file
and then putten in the PAStepper.m the following in a method
[self.stepperDelegate didDecrement];
in the controller i want to take the delegate i did this
.h
#interface OCSideCartViewController : UIViewController<StepperDelegate>
.m
- (void)viewDidLoad
{
[super viewDidLoad];
PAStepper *stepper = [[PAStepper alloc]init];
stepper.stepperDelegate = self;
}
-(void)didIncrement{
NSLog(#"inc");
}
-(void)didDecrement{
NSLog(#"dec");
}
knowing that this class is viewController that contain a table that every cell have PAStepper .. all i wanted that the delegate call didIncrement and didDecrement whenever i press the buttons
When you call this method
[self.stepperDelegate didDecrement];
NSLog you stepperDelegate and ensure it is not null. Can you confirm the method which calls your delegate is being called?
you can call this in your pastapper.h file
if ([stepperDelegate respondsToSelector:#selector(didIncrement)])
{
[stepperDelegate performSelector:#selector(didIncrement)];
}
I can´t download the project, so i am guessing..
Is the Stepper in the Interface Builder?
If yes you don´t have to allocate it.
Make an Outlet Connection of the Stepper in the OCSideCartViewController.
Post this in OCSideCartViewController:
- (void)viewWillAppear:(BOOL)animated{
self.stepper.stepperDelegate = self;
[super viewWillAppear:animated];
}
If the Stepper is not an Outlet, you have to add it to your ViewControllers view after setting it´s bounds..