iPad dismiss popover with button within the popover itself - ipad

I have a button in my popover controller. I want to use it to dismiss the popover, so I am trying to access a method (dismissPopover) of the presenting view controller (the "root" view controller).
Note: the method to dismiss the popover is already set up and working, in the root VC, which is the delegate. If I call it it will dismiss the popover. I just need to access the method from the popover.
To do this I set up a property in the AppDelegate, and get an instance of the rootVC like this: self.rootController = (ViewController*)self.window.rootViewController;. Then I imported the root VC class and the AppDelegate to the popover's view controller's class, as below. Seems to give me access to the rootVC, and the methods, but the results do not fire the method. Any idea what I am missing here?
#import "ViewController.h"
#import "AppDelegate.h"
Action connected to button:
- (IBAction)dismissPopover:(id)sender {
//Checking the button works, it does:
NSLog(#"dismissPopover, from popover");
//Trying to get an instance of the rootViewController, the "presenting view controller"
ViewController *rootVC = [(AppDelegate *)[[UIApplication sharedApplication] delegate] rootController];
//trying to access the method in the rootVC that dismisses the popover
[rootVC dismissPopover];
//Tried the following code, does nothing:
//[self dismissPopoverAnimated:YES];
}
NOTE: I ended up abandoning the use of a popover for this as it became a bit over complicated. I tried loading my view controller into a UIView (so I could load the contents of a nib to a pop-up view). That also became a bit complicated. So, for now I am just building my desired interface in a UIView programatically. So far works great.

dismissPopoverAnimated: is a method of UIPopoverController class. so, you need a popover controller reference in your 'root' view controller.
MyRootViewController.myPopoverController = thePopover;
the button is in your 'root' view controller, and in it's action method:
[self.myPopoverController dismissPopoverAnimated:YES];

In iOS 8, you can dismiss the popover (if it's coming from a segue, at least) with dismissViewControllerAnimated:completion: from within the popover. Doesn't work in iOS 7 (or below), however.

Popover automatically dismissed when clicking outside it , as you order a button to dismiss it you can simply use the following code inside your dismissPopover method :
[self.popoverController dismissPopoverAnimated:YES];
you don't need all this tedious work !

[self dismissViewControllerAnimated:YES completion:nil];
is the solution;
you just need an IBoutlet or add target to your button and then call above line

I had the same problem
just do in your buttonClickMethod:
[yourPopoverController dismissPopoverAnimated:YES];
hope you help!
cheers

Related

Change to different VIewController on button press

I have a functioning app, and I'd like to just add a new view and have an existing button change views with an IBAction function. I've set up the following and get no response. Thanks for any help.
MainViewController.h
- (IBAction)showSettings:(UIButton *)sender;
MainViewController.m
-(void)showSettings:(UIButton*)btn{
SettingsViewController *oView = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:nil];
[self.navigationController pushViewController:oView animated:YES];
}
SettingsViewController.h (the new view) is relatively empty.
SettingsViewController.m
boilerplate
Three things to make sure:
showSettings: gets called when the button is tapped (if not then perhaps you didn't connect the button tap event to the action at all)
SettingsViewController instance gets alloc and initialised
self.navigationController is not nil (if it's nil perhaps the current view controller is not embed in a navigation controller in the first place?).
Update:
Now we see the issue is #3. To embed your first view controller to a UINavigationController so you could push the second view controller:
Select your first view controller in storyboard
Select (menu) Editor -> Embed In -> Navigation Controller
Have you wired up your button's TouchUpInside event to your showSettings: method? This is normally done in Interface Builder with a control-drag. If you set a breakpoint on the first line of showSettings:, do you hit the breakpoint when you press the button? If not this is likely your issue.

Some code not executing in a method called from another ViewController

My problem
I have a standard UIViewController. With the press of a button, it loads a form sheet modal view controller. When dismissing this modal view with the press of a UIBarButtonItem I call a method by doing:
ViewController *main = [[ViewController alloc] initWithNibName:nil bundle:nil];
[main updateLabel];
In the method -(void)updateLabel in the main ViewController I'm setting the text of a label, but the label won't change. But I know the function gets called, because if I do a NSLog(#"Method call test); instead of label.text = #"Test" I can see the message in console.
What am I doing wrong? It must be the way I'm calling the method in the main ViewController, because I can easily change the label anywhere else.
What I want to do:
When dismissing a modal view controller, I want a method to be called in the main view controller, and in this case change the text of a label.
Thanks for your help!
You're creating a new instance of ViewController with that code, not getting a pointer to the one you already have.
If ViewController is the controller that presented the modal view, then you can get a pointer to it with,
ViewController *main = self.presentingViewController;
A better way to do this would be to use the delegate pattern.
https://developer.apple.com/library/ios/documentation/general/conceptual/DevPedia-CocoaCore/Delegation.html
The following is a design pattern suggestion
The modal view controller shouldn't know how to dismiss itself, that is the responsibility of the presenting view controller. After all, it could have been presented in many different ways (modally, popover, push navigation). Using the delegate pattern, the modal view controller would tell its delegate that it should be dismissed when the bar button item gets pressed. The delegate, which is the presenting view controller, would then dismiss the modal view and update the label mentioned in your question.

ModalView crashes in iOS7

I'm having an app crash in iOS7, but is working on iOS6. While debugging the next code from my AppDelegate, I checked that in iOS7 the next function is executed and then the modal view controller is loaded.
- (void)presentModalWebViewWithURL:(NSURL *)url title:(NSString *)title
{
[self.modalWebViewController dismissModalViewControllerAnimated:YES];
self.modalWebViewController = [[[MyModalWebViewController alloc] initWithURL:url] autorelease];
self.modalWebViewController.title = title;
UINavigationController *nav = [self.modalWebViewController modalNavigationControllerWithTarget:self dismissSelector:#selector(dismissModalWebView)];
[self.window.rootViewController presentViewController:nav animated:YES completion:NULL];
}
In iOS6, I checked that the function stops the execution in the last line until the modal view controller is loaded.
What happens in iOS7 is that when the modal view controller tries to load running viewWillAppear, I was able to check that the modal view controller has changed all the values and even the properties are pointing to objects of different types. I guess that they are being deallocated but I can't figure out why and how to fix it. Any suggestions?
When you dismiss a modal view controller, you're supposed to call the dismiss method on the view controller that presented the view controller. Also the dismissModalViewControllerAnimated: method is deprecated, you should instead use dismissViewControllerAnimated:completion:. So looking at your code, you should probably be calling the dismiss method on self.window.rootViewController, since that's what you're presenting modal views from.
Also, not knowing how the rest of your code looks, I'm assuming the first time this gets called, self.modalWebViewController is nil, so you probably want to check if self.modalWebViewController is set to something before you call dismiss, and also to set it to nil any time you do dismiss it.

How to call method on presenting view controller from modal view controller

I have a modal view controller that I called in from another view controller. Upon dismissal of the modal view controller, I want a method to be called on the view controller that presented that modal view. What is the easiest way to do this?
I tried doing this in my modal view controller: [(ParentViewController*)self.presentingViewController foo]; before calling [self dismissViewControllerAnimated:YES completion:nil];.
Xcode gives me an error saying foo isn't recognized, even though it is defined and prototyped in the controller. If your solution involves blocks, I really don't understand them so I would appreciate it if you would add more detail. Thanks.
ParentViewController.h
#interface ParentViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
{
NewAssignmentViewController *newAssignmentViewController;
TableViewDataSource *data;
}
-(void)foo;
#end
You need to get a correct reference to your presenting controller like this:
ParentViewController *presenter = [(UITabBarController *)self.presentingViewController viewControllers][0]; // 0 is assuming that ParentViewController is in the first tab. Change if necessary
[presenter foo];
The other way to do it would be to use delegation, but that's an answer for another time.
If you are using a Storyboard segue to present your view controller you could dismiss it using an Unwind Segue. An unwind segue is a special kind of segue that unwinds the presented view controllers back to a presenter.
To accomplish this, you would create a method in the presenting view controller with the following signature:
- (IBAction)unwindAction:(UIStoryboardSegue*)unwindSegue;
This is different than a standard IBAction because the parameter type is a UIStoryboardSegue* instead of the normal id type (it doesn't have to be named unwindSegue:, it could be modalViewFinished: or whatever you like - the important part is that it has a return type of IBAction and a parameter type of UIStoryboardSegue*).
Once you have this method defined, in your storyboard you control-drag from the modal view controller icon (below its view, in the little bar of icons) and release the connection on the green exit sign. This will create an unwind segue, which you should give an identifier in the attributes inspector. Unwind segues will not show up visually in the storyboard canvas, so you will have to find it in the list of items on the left side of the canvas (this is collapsed by default, expand it by clicking the little circular button in the lower left hand corner of the canvas).
Once you've done that, rather than calling [self dismissViewControllerAnimated:YES completion:nil], just call [self performSegue:<Identifier you gave the unwind segue>] instead. During this process the unwindAction: method defined on the presenting view controller and the prepareForSegue: method on the modal view controller should be invoked. You can do whatever cleanup you need to do in these methods (calling the foo method from unwindSegue:, for example).
You call the method on the UIViewController that is your MainView, and pass it your UIViewController you want to be the ActionSheet.
UIActionSheet *actionSheetController =[[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"show otherview", nil];
[self presentModalViewController:actionSheetController animated:YES ];
To dismiss the UIActionSheet, dimissWithClickedButtonIndex:animated: is a method for the UIActionSheet that you can implement. The method can be called by whoever (so if you want to dismiss it from your mainview have a reference to the action sheet and do something like
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
{
switch (buttonIndex){
case 0:
{
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
}
break;
case 1:
{
MyClass *myclassObject = [[MyClass alloc]init];
[myclassObject foo];
}
}
}
The method is also called whenever the 'cancel' button is clicked by the user.
Use this ModalViewControllers link for better understanding...!

ViewDidAppear not called in main view when modal view is presented over a popover

I'm trying to use a popover as an intermediary menu between my main view and a modal view controller. I can successfully present the Modal view controller from the popover by using the following code:
UIStoryboard *storyboardiPad = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
cbwEditControlPanel *editCP = [storyboardiPad instantiateViewControllerWithIdentifier:#"EditCP"];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:editCP];
[nav setToolbarHidden:NO];
[nav setModalPresentationStyle:UIModalPresentationFullScreen];
[nav setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:nav animated:YES completion:nil];
self.modalInPopover = NO;
The problem I'm running into is that when the EditCP modal view controller is dismissed, the main view controller never updates. I have a pagecontroller on the main view that should be updated to reflect the number of pages as set in the EditCP modal view controller, but for some reason the modal view controller being called from the popover prevents the main view controller from updating the pagecontroller. I've even tried calling the main view's "View Will Appear" method from the popover or modal view when they are dismissed, but even if the 'viewWillAppear' method is called the pageController will not update!
Any ideas what is preventing the pageController from updating? I even passed a reference to the pagecontroller to the modal view and tried to update it there, but it seems that from the time the popover is presented until it is dismissed, I cannot update the number of pages on the PageController.
Thank you!
So this is an old question but I also came across a similar problem recently when using a popover. My solution was to use an unwind segue to trigger my parent view to perform some action. In my case my parent view contains contact information and the popover contains a list of cites. All I wanted to do was to have the parent view update with the new city once the user selected it from the popover. So in my parent view I create my unwind function as follows:
In the .h:
- (IBAction)unwindToContactTVC:(UIStoryboardSegue *)unwindSegue;
In the .m:
- (IBAction)unwindToContactTVC:(UIStoryboardSegue *)unwindSegue
{
[self updateTableForOffice];
}
In the above .m file is where you would have the logic to do whatever it is you want to in the parent view. To connect this unwind segue go to the child view in the storyboard and control drag from the view icon to the exit icon. You should see a pop up with the name of your unwind segue.
Finally, give that unwind segue a name and then in the child controller in the viewWillDisappear() function call the segue as follows:
- (void)viewWillDisappear:(BOOL)animated
{
[self performSegueWithIdentifier:#"unwind-to-contact-tvc" sender:self];
}
I hope that helps. If someone has a better solution let me know.
Well, I half solved the problem. The only way to get an update function when the popover disappeared was to stop using Storyboards and programmatically present the popover, using the main view as the delegate. I then was able to update correctly inside the popoverControllerDidDismissPopover method.
However, I am still interested in finding a way to update the pageControl when the modal is dismissed, before the popover is dismissed.

Resources