dismissing modalViewController of modalViewController - iphone

So I have a UITabBarController app and I want to display a login page, and so I did:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(userDidLogin:) name:UserDidLoginNotification object:nil];
LoginViewController* loginViewController = [[LoginViewController alloc] init];
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:0];
[self.tabBarController.selectedViewController presentModalViewController:loginViewController animated:NO];
[loginViewController release];
Inside my LoginViewController I can as well show another modalViewController:
- (void) twitterLogin: (UIViewController *) askingView
{
UIViewController *controller = [SA_OAuthTwitterController controllerToEnterCredentialsWithTwitterEngine: _twitter delegate: self];
if (controller) {
self.askingView = askingView;
[askingView presentModalViewController: controller animated: YES];
}
}
I have the following method where the askingView is the LoginViewController,
when I want to dismiss this I do:
[self.askingView dismissModalViewControllerAnimated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:UserDidLoginNotification object:nil];
However, this doesn't dismiss the LoginViewController and show the UITabBarController views.. it just dismisses my modalViewController shown from the LoginvVIewController. What am I doing wrong here? I am also getting the following error:
attempt to dismiss modal view controller whose view does not currently appear. self = <LoginViewController: 0x2aff70> modalViewController = <SA_OAuthTwitterController: 0x2d2a80>
2011-09-16 09:45:37.750 VoteBooth[4614:707] attempt to dismiss modal view controller whose view does not currently appear. self = <MainViewController: 0x29fec0> modalViewController = <LoginViewController: 0x2aff70>

In order to dismiss a modal view that is presented over another modal view, you have to call dismissModalViewControllerAnimated: on the parent of the parent. I have used this in some of my apps and it has worked beautifully for me (after many painstaking hours trying to figure it out). Here is exactly what I've used:
[[[self parentViewController] parentViewController] dismissModalViewControllerAnimated:YES];

if ([self respondsToSelector:#selector(presentingViewController)]) {
[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES]; // for IOS 5+
} else {
[self.parentViewController.parentViewController dismissModalViewControllerAnimated:YES]; // for pre IOS 5
}

If you have a dynamic UX and do not know how many parents to go to, you can use this recursive function to figure it out...
- (void) goHome
{
//Dismiss modal back to home page
int numberOfVcsToDismiss = [self findRootViewController:self];
[self dismissToRootVc:numberOfVcsToDismiss];
}
- (int) findRootViewController:(UIViewController*)vc
{
if(vc)
{
return 1 + [self findRootViewController:vc.presentingViewController];
}
return 0;
}
- (void) dismissToRootVc:(int)count
{
if(count == 1)
[self dismissViewControllerAnimated:YES completion:^{}];
if(count == 2)
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 3)
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 4)
[self.presentingViewController.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 5)
[self.presentingViewController.presentingViewController.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
//etc....
}

Related

Dismiss the popover view

I have a root view controller in which I load a sub view that contains three buttons. When I touch one of them a popover is shown. The popover contains an image view and a bar with a Done button. I want to dismiss this popover when the Done button is touched. To accomplish this I am using this code
- (IBAction)btnDone:(UIBarButtonItem *)sender {
[self.view removeFromSuperview];
[APPDELEGATE.parkDetail. popoverController dismissPopoverAnimated:YES];
// [APPDELEGATE.parkDetail.popoverController dismissPopoverAnimated:YES ];
}
and the popover is presented like this
- (IBAction)btnParkMap:(id)sender {
[popoverController dismissPopoverAnimated:YES];
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
} else {
parkMap * v = [[parkMap alloc]initWithNibName:#"parkMap" bundle:nil];
v.contentSizeForViewInPopover = CGSizeMake(350, 300);
popoverController = [[UIPopoverController alloc] initWithContentViewController:v];
CGRect popRect = CGRectMake(self.btnShowPopover.frame.origin.x+330,
self.btnShowPopover.frame.origin.y+170,
self.btnShowPopover.frame.size.width,
self.btnShowPopover.frame.size.height);
[popoverController presentPopoverFromRect:popRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
}
Try this code
[self dismissViewControllerAnimated:YES completion:nil];
Or try #nirav's ans
Try to write below code
[yourPopOverobject dismissPopoverAnimated:YES];
Let me know whether it is working or not..
Happy Coding!!!!!
The PopUpOver can beswitch off the default contextual menu of UIWebView. This is easy because we only need to set the CSS property “-webkit-touch-callout” to “none” for the body element of the web page. We can do this using JavaScript in the UIWebView delegate method “webViewDidFinishLoad:”…
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[webView stringByEvaluatingJavaScriptFromString:#"document.body.style.webkitTouchCallout='none';"];
}
- (IBAction)btnDone:(UIBarButtonItem *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
Try to check below code...
if ([popoverobject isPopoverVisible]) {
[popoverobject dismissPopoverAnimated:YES];
[popoverobject release];
}
}
#pragma mark -
#pragma mark UIPopoverController delegate
-(void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
//if (popoverController == popoverobject) {
[popoverobject release];
// }
}
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController {
NSLog(#\"popover about to be dismissed\");
return YES;
}
let me know is it working or not...

MBProgressHud not hiding after second look

I have a MBProgressHUD that I want to display when switching tabs. This is in my app delegate. I have this code here to display the HUD on only the first three tabs
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
if ([viewController isKindOfClass:[UINavigationController class]]) {
if (tabBarController.selectedIndex >= 3) {
UINavigationController *nav = (UINavigationController *) viewController;
[nav popToRootViewControllerAnimated:NO];
}
else {
UINavigationController *nav = (UINavigationController *) viewController;
HUD = [[MBProgressHUD alloc] initWithView:nav.view];
[nav.view addSubview:HUD];
HUD.labelText = #"Loading";
[HUD show:YES];
[nav popToRootViewControllerAnimated:NO];
}
}
}
The first time I view my page it works but going back to it a second time it doesn't hide. I have my [appDel.HUD hide:YES afterDelay:1.0]; in my viewDidAppear.
How can I get the HUD to hide every time I visit the page?
I think you may be adding the MBProgressHUD to a different view within the UINavigationController. Then you're popping to the root, and it's trying to remove an MBProgressHUD that doesn't exist. Try this (untested code)...
UINavigationController *nav = (UINavigationController *) viewController;
[nav popToRootViewControllerAnimated:NO];
if(![nav.visibleViewController.view.subViews containsObject:MBProgressHUD])
{
[MBProgressHUD showHUDAddedTo:nav.visibleViewController.view animated:YES];
MBProgressHUD.labelText = #"Loading";
}
else
{
[MBProgressHUD setHidden:NO];
}
you have to check if the MBProgressHUD view was already activated if so hid it, or simply do so:
if (!HUD) {
[self showLoadingHUD];
}

isBeingDismissed not set in viewWillDisappear:

I have some code to clean up in my viewWillDisappear:, which I only want to use when the view is moving back to the parent view controller.
- (void)viewWillDisappear:(BOOL)animated
{
if ([self isMovingFromParentViewController] || [self isBeingDismissed]) {
NSLog(#"isMovingFromParentViewController or isBeingDismissed");
// clean up
}
[super viewWillDisappear:animated];
}
The view can be presented in two ways: it can be pushed by a navigation controller, or presented as a modal view controller (from the same navigation controller). If it's pushed, then popped (pressing the back button), my clean-up code runs. If it it presented as a modal view controller, then dismissed, the code doesn't run.
I dismiss like so:
[rootViewController dismissModalViewControllerAnimated:YES];
My question is: why isn't isBeingDismissed set when I dismiss my view controller?
If this is the first view controller in a modal navigation controller that's being dismissed, calling self.isBeingDimissed() from viewWillDisappear: returns false.
However, since the entire navigation controller is being dismissed, what actually works is self.navigationController?.isBeingDismissed(), which returns true.
As #Yuval Tal mentioned, this flag does not work when you're dismissing controller that is embeded inside navigation controller. Here's an extension that I use:
extension UIViewController
{
var isAboutToClose: Bool {
return self.isBeingDismissed ||
self.isMovingFromParent ||
self.navigationController?.isBeingDismissed ?? false
}
}
It can be easily extended when you find another case when standard .isBeingDismissed won't work. And if you find, let us, let me know in comments.
Your issue is how you are dismissing your modal view. How is rootViewController being defined?
When I call [self dismissModalViewControllerAnimated:YES] then [self isBeingDismissed] evaluates to true.
When I call [parentViewController dismissModalViewControllerAnimated:YES] then [self isBeingDismissed] evaluates to true, whereby parentViewController is the UIViewController that presented the modal view (note: not a UINavigationController).
If by some chance you came here trying to use isBeingDismissed on a non-modally presented view controller, you can always check the topViewController property of your navigationController, for instance:
if navigationController?.topViewController != self {
return
}
viewController.isBeingPresented == NO;
[rootVC presentViewController:viewController animated:NO completion:^{
viewController.isBeingPresented == NO;
viewController.isBeingDismissed == NO;
[viewController dismissViewControllerAnimated:NO completion:^{
viewController.isBeingDismissed == NO;
}];
viewController.isBeingDismissed == NO; // is not work
}];
viewController.isBeingPresented == YES; // is work
viewController.isBeingPresented == NO;
[rootVC presentViewController:viewController animated:NO completion:^{
viewController.isBeingPresented == NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
viewController.isBeingDismissed == NO;
[viewController dismissViewControllerAnimated:NO completion:^{
viewController.isBeingDismissed == NO;
}];
viewController.isBeingDismissed == YES; // is work
});
}];
viewController.isBeingPresented == YES; // is work

Removing a second viewcontroller's view after dissmissing mail controller

A second viewcontroller has mailcontroller and after finishing mail, it post a message to the mainviewcontroller to remove the secondviewcontroller's view. but it's not happening. The mailcontroller appearing and disappearing seem to interferes with finish function of the mainviewcontroller.
secondviewcontroller:
[self dismissModalViewControllerAnimated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"finish" object:nil];
mainviewcontroller:
-(void) finish:(NSNotification *)notif {
[MyviewController.view removeFromSuperview];
}
The removal of the second view controller should be delayed until your modal controller is really removed. What I have done is following:
[self dismissModalViewControllerAnimated:YES];
m_shouldHide = YES;
And then:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ( m_shouldHide )
{
[self dismissModalViewControllerAnimated:YES];
m_shouldHide = NO;
}
}

How to dismissPopoverAnimated on iPad with UIPopoverController in MKMapView (SDK3.2)

I have a MKMapView (also a UIPopoverControllerDelegate) with Annotations. This MapView has, in the MKTestMapView.h file, a UIPopoverController* popoverController defined in the #interface and a #property (nonatomic, retain) UIPopoverController* popoverController; defined outside of the #interface section. This controller is #synthesized in the MKTestMapView.m file and it is released in the - (void)dealloc section. The Annotations in this MapView have rightCalloutAccessoryViews defined to the following:
- (void)mapView:(MKMapView *)mapView2 annotationView:(MKAnnotationView *)aview calloutAccessoryControlTapped:(UIControl *)control{
...
CGPoint leftTopPoint = [mapView2 convertCoordinate:aview.annotation.coordinate toPointToView:mapView2];
int boxDY=leftTopPoint.y;
int boxDX=leftTopPoint.x;
NSLog(#"\nDX:%d,DY:%d\n",boxDX,boxDY);
popoverController = [[UIPopoverController alloc] initWithContentViewController:controller];
popoverController.delegate = self;
CGSize maximumLabelSize = CGSizeMake(320.0f,600.0f);
popoverController.popoverContentSize = maximumLabelSize;
CGRect rect = CGRectMake(boxDX, boxDY, 320.0f, 600.0f);
[popoverController presentPopoverFromRect:rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];
...
}
Now here comes the fun part. First of all, I am not sure if I need maximumLabelSize and the rect to be the same size. I am new to the popovercontroller so I am playing this by ear..
Okay, the popover shows. Now to dismissing it. I can click anywhere on mapView2 and the popover goes away...but I need the user to click a button in the view if they change anything. URGH!
The docs show:
To dismiss a popover programmatically,
call the dismissPopoverAnimated:
method of the popover controller.
Well, here is the problem: By definition of how the popoverController works, you are clicking inside the view of the displayed popover (to click the button) but have to trigger the dismissPopoverAnimated: method of the controller that launched this popover view, in my case, the popoverController inside the MKTestMapView.m file.
Now, having said all that, remember, [popoverController release] doesn't happen until:
- (void)dealloc {
[popoverController release];
[mapView release];
[super dealloc];
}
So, do i just do the following inside the button (messy but may work):
(Assuming my popover view is a TableView) In the:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MKTestMapView * mKTestMapView = [[MKTestMapView alloc] init];
[[mKTestMapView popoverController].dismissPopoverAnimated:YES];
}
Here is my issue: I cannot figure out whether doing the above gives me a reference (if there is such a thing) to the existing view that is on the screen -- and therefore the view that is the owner of that popoverController. If it is as simple as
[[[self parentView] popoverController].dismissPopoverAnimated:YES];
I will shoot myself cos I don't think that is the correct syntax either!
This should be easy...yet I am lost. (probably just frustrated with so many iPad differences that I am learning).
Can anyone explain more?
I had the same problem... I had a neat "close" button (X) in the top of my view loaded by the popover, but it didn't work. In my universal app it will be presented as a new view, so that code should stay.
What I did now was that I added the following to my detailedPinView (the view the popover loads):
in the detailedPinView.h file:
#interface detailedPinView : UIViewController {
[...]
UIPopoverController *popover;
[...]
}
-(void)setPopover:(UIPopoverController*)aPopover;
In the detailedPinView.m file:
- (void)setPopover:(UIPopoverController*)aPopover
{
popover = aPopover;
}
The X button closes the view using an IBAction, this is what I did there:
In the detailedPinView.m file:
-(IBAction)releaseDetailedView:(UIButton *)sender
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if (popover != nil)
{
[popover dismissPopoverAnimated:YES];
}
else {
NSLog(#"Nothing to dismiss");
}
}
else{
[self.parentViewController dismissModalViewControllerAnimated: YES];
}
}
In the class loading the my map and the popover view I added the following code:
[...]
-(void)mapView:(MKMapView *)theMapView annotationView:(MKAnnotationView *)pin calloutAccessoryControlTapped:(UIControl *)control
{
UIViewController *detailController = [[detailedPinView alloc] initWithNibName:#"detailedPinView"
bundle:nil
annotationView:pin];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
UIPopoverController* aPopover = [[UIPopoverController alloc] initWithContentViewController:detailController];
[aPopover setDelegate:self];
[aPopover setPopoverContentSize:CGSizeMake(320, 320) animated:YES];
[detailController setPopover:aPopover];
[detailController release];
[mapView deselectAnnotation:pin.annotation animated:YES];
self.popoverController = aPopover;
[mapView setCenterCoordinate:pin.annotation.coordinate animated:YES];
[self.popoverController presentPopoverFromRect:CGRectMake(382,498,0,0) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
else
{
[self presentModalViewController: detailController animated:YES];
}
[detailController release];
}
[...]
I don't know if the was the answer you were hoping for, I think it might be a bit of a messy way to do it... but giving the time schedule this worked like a charm :)
Here is another simple solution.
I found that we should follow the following steps for clearly dismissing popovers.
dismiss a popover.
release a view loaded by the popover.
Before iOS8, almost all of us may release a view loaded by a popover first, and then we programmatically dismiss the popover.
However, in iOS8, we do the steps in revers.
Before iOS8, my code of dismissing a popover
// creating a popover loading an image picker
picker = [[UIImagePickerController alloc] init];
...
pickerPopover = [[UIPopoverController alloc] initWithContentViewController:picker];
[pickerPopover presentPopoverFromRect:aFrame inView:aView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
// dismissing the popover
[picker.view removeFromSuperview]; // (1) release a view loaded by a popover
[picker release], picker = nil;
if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ) {
[pickerPopover dismissPopoverAnimated:YES]; // (2) dismiss the popover
}
In iOS8, the dismissing code part should be changed as below,
if( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ) {
[pickerPopover dismissPopoverAnimated:YES]; // (2) dismiss the popover first
}
[picker.view removeFromSuperview]; // (1) and then release the view loaded by the popover
[picker release], picker = nil;