When the user pressed an 'add' button a modal view pops up for them to enter information. I have a 'cancel' button in the top left of a navigation bar and I want it to dismiss the current view controller when it is pressed. How do I set an object as the class's delegate? I understand creating protocols and implementing its methods but I cannot seem to make the delegate be set. When running the debugger my [self delegate] in the 'add' view controller is always nil.
Are you spawning the modal viewController through a segue set up in your Storyboard? If so, then in the prepareForSegue: method you would set the delegate there.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([identifier isEqualToString:#"userGuideSegue_home"]){
UserGuideViewController* vc = segue.destinationViewController;
[[segue destinationViewController] setDelegate:self];
}
}
On the other hand, if you are setting up the modal viewController entirely through code, then you would create an instance of the modal viewController then set it's delegate.
- (void)showModelView:(NSString*)viewName
{
// code ripped out of project so a bit specific
if ([viewName isEqualToString:#"userGuide_name"]) {
modalViewController = (UserGuideViewController * )
[[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:NULL]
instantiateViewControllerWithIdentifier:#"UserGuide"];
}
modalViewController.delegate = self;
modalViewController.modalPresentationStyle = UIModalPresentationFormSheet;
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
modalViewController.view.frame = [[UIScreen mainScreen] applicationFrame];;
[self presentViewController:modalViewController
animated:YES
completion:^{
//put your code here
}];
}
Of course all this assumes you have defined a delegate property on your modal viewController.
If you created the view in IB, Control-drag the button into the ViewController's header file and add an IBOutlet. Inside of that method in the .m file you can
[self dismissModalViewControllerAnimated:YES];
alternatively you can create the button programmatically:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(processCancel:)];
-(void)processCancel:(UIBarButtonItem *)item{
[self dismissModalViewControllerAnimated:YES];
}
#interface MyViewController : UIViewController {
id delegate;
}
#property (nonatomic,retain) id delegate;
#synthesize delegate;
This should do the job, you can now use [MyViewController setDelegate:self] before showing the modal view and call [[self delegate] dismissModalViewControllerAnimated:YES] in the cancel button tapped event in MyViewController
Related
I'm trying to implement SWRevealViewController on this scenario:
From my main viewController:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SWRevealViewController *SWR = [storyboard instantiateViewControllerWithIdentifier:#"SWRevealViewController"];
[self presentViewController:SWR animated:YES completion:nil];
}
From my green view controller:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
self.reveal = [[SWRevealViewController alloc] init];
self.reveal.delegate = self;
self.menu.target = self;
self.menu.action = #selector(revealToggleAction:);
[self.view addGestureRecognizer:self.reveal.panGestureRecognizer];
NSLog(#"viewDidLoad");
}
-(void)revealToggleAction:(id)sender
{
[self.reveal revealToggle:self];
}
The revealToggle action is been call but doesn't do anything. It doesn't load the rear view controller. Any of you knows this happening or what I'm doing wrong?
Assuming that you are showing the side bar menu from right side.
First Embed your first view controller to navigation controller, then in your first view controller viewdidload() or viewDidAppear method add below mentioned code i.e.
//this is your side menu view controller.
UIViewController *sideMenuController =
[self.storyboard instantiateViewControllerWithIdentifier:#"YourSideMenuIdentifier"];
//this is the navigation controller embed to your green view controller.
UINavigationController *nc1 =
(UINavigationController *)[self.storyboard instantiateViewControllerWithIdentifier:#"YourNavigationControllerIdentifier"];
//This is your reveal view Controller.
SWRevealViewController *revealViewController =
[[SWRevealViewController alloc]initWithRightViewController:sideMenuController frontViewController:nc1];
[self.navigationController pushViewController:revealViewController animated:YES];
[self.navigationController setNavigationBarHidden:YES];
This will navigate to Controller i.e Green View Controller.
then in your green view controller viewdidload() or viewDidAppear method add below mentioned code i.e.
//GreenViewController.h file
#interface GreenViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIBarButtonItem *sideBarItem;
#end
//Your GreenViewController.m file
_sideBarItem.target = self.revealViewController;
_sideBarItem.action = #selector(rightRevealToggle:);
SWRevealViewController *revealController = [self revealViewController];
[self.view addGestureRecognizer:revealController.panGestureRecognizer];
Note: For more details, check below mentioned link
http://www.appcoda.com/ios-programming-sidebar-navigation-menu/
You need set SWRevealViewController is the initial view controller.
You are creating a new instance of SWRevealViewController.
I think if you set the self.reveal to self.revealViewController it will work.
My first view in the viewDidLoad has the following code
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Dialpad" bundle:nil];
self.vc = [sb instantiateViewControllerWithIdentifier:#"DialpadBoard"];
self.vc.delegate = self;
The header file contains the definition of the view controller
#property (nonatomic, retain) DialpadTableViewController *vc;
after catching an event the view loads a new modal view
- (void)handleEvent:(UIGestureRecognizer*)recognizer {
[self presentViewController:self.vc animated:YES completion:NULL];
}
The view also contains the method to dismiss the modal view:
- (void) dialpadControllerDidCancel:(SearchDialpadTableViewController *)controller {
[self dismissViewControllerAnimated:YES completion:nil];
}
The last method never gets called.
The problem is that the modal view when it is loaded has nil self.delegate. The new modal view is loaded from the storyboard as seen below. Why the delegate is nil? I cannot how a segue since the view is in another storyboard.
you can try this
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Dialpad" bundle:nil];
UINavigationController *nav= [sb instantiateViewControllerWithIdentifier:#"DialpadBoard"];
((SearchDialpadTableViewController *)[nav viewControllers][0]).delegate = self;
[self presentViewController:nav animated:YES completion:NULL];
Since we have the nav let's take the first controller and assign the delegate
the trick ;)
((SearchDialpadTableViewController *)[nav viewControllers][0]).delegate = self;
Does SearchDialpadTableViewController define a delegate protocol and does it have a property that is specific to that protocol?
The header for that file should look something like:
#protocol ViewControllerDelegateProtocol <NSObject>
- (void)dialpadControllerDidCancel:(SearchDialpadTableViewController *)controller;
#end
#interface ViewController : UIViewController
#property (weak, nonatomic) id<ViewControllerDelegateProtocol> searchPadDelegate;
#end
Then when the user taps Done which is I'm assuming what you're trying to do (send a delegate message when that happens). You would write something like
- (IBAction)donePressed:(id)sender
{
if ([self.searchPadDelegate respondsToSelector:#selector(dialpadControllerDidCancel)]) {
[self.searchPadDelegate dialpadControllerDidCancel:self];
}
}
you must be certain, that self.vc is a class, that you expected. It can be also NavigationController
I have a problem.
I write code in button touch event. Run project and click button. Then i get a black screen.
- (IBAction)ff:(id)sender {
SecondViewController *viewController = [[SecondViewController alloc] init];
[self presentViewController:viewController animated:YES completion:nil];
}
1) Add button in XIB or Storyboard.
2) Create a button in your viewController.h file
__weak IBOutlet UIButton *yourButton;
3) In the same file, add selector of the button:
-(IBAction)yourButton_pressed:(id)sender;
4) Go to XIB or Storyboard, open Connection Inspector, Drag and drop from yourButton to the button added in XIB or Storyboard.
5) Same way, Drag and drop from yourButton_pressed to the button added in XIB or Storyboard. It will ask you for the action type like TouchUpInside, TouchUpOutside. Select TouchUpInside for now.
6) Present modal view controller:
YourViewController *viewController = [[YourViewController alloc]initWithNibName:#"YourView" bundle:nil];
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
[viewController release];
7) Enjoy and Upvote :D
Just select the Button from the MainStoryboard and hold CTRL and drag it to the view controller and select present modally.
And remove the IBAction from the implementation and remove the sent events from the MainStoryboard for that button.
If you want to go to SecondViewController, you can always use prepareForSegue method.
But first make a connection, see screenshots here: http://imgur.com/a/CJFwy
Then add this code to your viewController:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowSecondVC"]) {
SecondViewController *secondVC = [segue destinationViewController];
}
}
I am presenting a modal view controller on the iPad which changes the presenting view controller while presented. For example:
A view controller VC presents the modal view controller when the user selects a cell in a table view.
The user selects an item on the modal view controller and another VC instance is opened in place of the first. Importantly, the view controller instance replacing the first is of the same type.
The modal view controller cannot be dismissed or an EXC_BAD_ACCESS exception occurs.
The failing dismiss is understandable: the presenting view controller is no longer available. Basically, how would I dismiss this presented modal view controller from a different presenting view controller?
The code I already have is:
ViewController1.m
- (void)showModalViewController:(UIViewController *)viewController
{
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissModalViewController)];
[self presentViewController:navigationController animated:YES completion:nil];
}
- (void)dismissModalViewController
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
Thanks for your suggestions but I solved the issue by using delegation. The presented view controller defined a delegate to notify the presenter when an action occurred.
ChildViewControler.h:
#protocol ChildViewControllerDelegate <NSObject>
- (void) childView:(ChildViewController *)childView didSelectItem:(Item *)item;
#end
ChildViewController.m:
// in interface
#property (nonatomic, weak) id <ChildViewControllerDelegate> delegate;
// in implementation
- (void)closeView:(Item *)anItem
{
[self.delegate childView:self didSelectItem:anItem];
}
ViewController1.m:
- (void)showModalViewController:(UIViewController *)viewController
{
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissModalViewController)];
// Different view controller types may be passed here so check is required...
if (viewController.class == [ChildViewController class]) {
((ChildViewController *)viewController).delegate = self;
[self presentViewController:navigationController animated:YES completion:nil];
}
- (void)childView:(ChildViewController *)childView didSelectItem:(Item *)item
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
// Perform action required with 'item'
}
You can try to change
self.presentingViewController
(The view controller that presented this view controller or its farthest ancestor.)
property in your modal View Controller before dismissing.
Here is your problem:
//...
viewController.navigationItem.rightBarButton = [[UIBarButton alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissModalViewController)];
//...
- (void)dismissModalViewController
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
You try to dismiss presenter view controller (that is currently seems to be swithced to another already) instead of presented modal view controller (in your case it UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];)
so (if presenters view controllers not the tabs of tabViewController or not stored in navigationController's stack or somewhere else) you must to store reference to it somewhere else than in presenter view controller which will be switched and could be deallocated.
As per document presentingViewController is a readonly property.
You could not modify it.
#property(nonatomic,readonly) UIViewController *presentingViewController NS_AVAILABLE_IOS(5_0);
I have not tested this code but there may be error in dismissModalViewController.
please put break point on this method the first line is perfect may your second line may cause error,may self.tableView is not accessible or self.tableView indexPathForSelectedRow may be nil.
- (void)dismissModalViewController
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
}
Thanks.
I have a navigation based application.On click of a button on the navigation bar in the first screen , I am able to push another view controller as follows :
-(void) buttonClicked:(id)sender
{
UIViewController* mv = [[SecondViewController alloc] init];
[[self navigationController] pushViewController:mv animated:YES];
}
Now i have a UIView(separate .h and .m files) as part of the first screen. On click of a button in the UIView, i want to push the SecondViewController.
I have tried the following :
UIViewController* mv = [[SecondViewController alloc] init];
UIViewController * home=[[FirstViewController alloc]init];
[[home navigationController] pushViewController:mv animated:YES];
It doesnt work!! Kindly help
UIViewController* mv = [[SecondViewController alloc] init];
UIViewController * home=[[FirstViewController alloc]init];
[[home navigationController] pushViewController:mv animated:YES];
The problem here is that home isn't part of the navigation stack, so [home navigationController] is surely nil. I'm not quite clear on what you're trying to do here, but just creating a view controller doesn't mean that it's actually part of the view controller graph.
Why would it work? Randomly creating view controllers whose view is not even visible, is not the solution. You can either keep a reference to the VC in the view like this:
#imlementation ViewController
- (id) init
{
// ...
aView = [[CustomView alloc] init];
aView.viewController = self;
// ...
}
#end
#interface CustomView
#property (assign) ViewController *viewController;
#end
Or you can search the responder chain at runtime:
UIResponder *next = [view nextResponder];
while (next)
{
if ([next isKindOfClass:[ViewController class]])
{
break;
}
next = [next nextResponder];
}
And now "next" will contain the view controller (or nil if it can't be found).
Try using the same navigationController to push view, this keeps the same stack of ViewControllers.
UIViewController* mv = [[SecondViewController alloc] init];
[[self navigationController] pushViewController:mv animated:YES];
[mv release];
I see your problem now! You need to #import your FirstViewController, then #class it. Then do your push.
So:
//.h
#import "FirstViewContoller.h"
#class FirstViewController;
#interface...
//.m
-(void)return {
FirstViewController *firstview = [[FirstViewController alloc]init(withnibname:)];
[firstView.navigationController pushViewController: firstView.navigationController.topViewController animated: TRUE];
}
If I am not wrong, your UIView though is in separate files, is still added to the screen from a UIViewController class.
Simply, post a notification from UIView to your FirstViewController class where you have access to the navigation controller. Then push the SecondViewController from there.
You Can use this. It Works very well for me:-
Firstly Create Object of AppDelegate in UIView Class and initialize it. Then create Navigationcontroller object in Appdelegate.h :-
#property(strong,nonatomic) UINavigationController *navControl;
In your UIView Class implement this code where you want to push :-
ViewController *objview = [[ViewController alloc]init]; [appDelegate.navControl pushViewController:objview animated:YES];