16
votes

This is my view (controller) hierarchy:

  • UITabBarController (as the rootViewController of the app)
  • UINavigationController (as the viewController for one of the tabBar tabs)
  • UIViewController (as the rootViewController of the UINavigationController)
  • UICollectionView (as a subview)
  • MyViewController.view (as a section header view of the UICollectionView)

And so, I need to present a modal view controller from MyViewController. I have tried doing it with

[self presentViewController:modalVC animated:YES completion:nil];

and although it worked, Xcode warned me that "Presenting view controllers on detached view controllers is discouraged", and rightly so, because the modalVC only fills the view of the collection view header, which is not full screen which I'm after.

All other options that I have tried:

UITabBarController *tb = (UITabBarController *)self.view.window.rootViewController;
[tb presentViewController:modalVC animated:YES completion:nil];

or...

UINavigationController *nc = (UINavigationController *)tb.selectedViewController;
[tb presentViewController:modalVC animated:YES completion:nil];

or...

UICustomViewController *cv = (UICustomViewController *)nc.topViewController;
[vc presentViewController:modalVC animated:YES completion:nil];

present the modalVC full screen as desired, however, when I dismiss the modalVC by calling

[self dismissViewControllerAnimated:YES completion:nil];

from within modalVC itself, modalVC indeed dismisses itself, but I am left with a black screen. A little debugging revealed that after dismissing modalVC, self.view.window.rootViewController becomes nil.

Any idea why this is happening and how to resolve this?

EDIT

This is an iPhone app. The black screen happens on both iOS7 and iOS8. Also, below is the method where I initiate MyViewController

#pragma mark - UICollectionViewDelegate methods

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {

    self.myViewController = [[MyViewController alloc] initWithNibName:NSStringFromClass([MyViewController class]) bundle:nil];

    return self.myViewController.view.frame.size;
}
4
Can you show your setup of MyViewController and MyViewController.view?Aaron Brager
Aaron, I have updated the question. Is this what you were asking for? I don't do any additional setups in MyViewController itself.artooras

4 Answers

10
votes

I found the solution - this answer really helped. The trick was in dismissing the view controller. It should be done like this:

[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];

and not like this:

[self dismissViewControllerAnimated:YES completion:nil];

Although the author of the linked answer suggests that a better approach would be to use delegation (presentED VC would define a protocol and presentING VC would subscribe to it and then dismiss the presentED VC once it asks for it), it wasn't feasible in my case.

2
votes

Is this an iPad app? If yes, adding

modalVC.modalPresentationStyle = UIModalPresentationFullScreen

before

[self presentViewController:modalVC animated:YES completion:nil];

in MyViewController might do the trick.

1
votes

I had the black screen problem after presenting a screen with presentViewController: and dismissing it with dismissViewControllerAnimated:. My problem was that the dismiss command was unloading the entire view structure. My problem was resolved setting the modalPresentationStyle to UIModalPresentationOverFullScreen, as this:

viewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
[self presentViewController:viewController animated:YES completion:nil];

I got the solution from here.

0
votes

I find some information in Apple's UIViewController file

//The next two methods are replacements for presentModalViewController:animated and //dismissModalViewControllerAnimated: The completion handler, if provided, will be invoked after the presented controllers viewDidAppear: callback is invoked.

  • (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion NS_AVAILABLE_IOS(5_0); // The completion handler, if provided, will be invoked after the dismissed controller's viewDidDisappear: callback is invoked.
  • (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion NS_AVAILABLE_IOS(5_0);

As you describled,you directly add view in UIViewController to another view . So viewDidAppear and viewDidDisappear are not invoked.I guess you'd better execute these two methods manually.