Dismissing a UIDocumentInteractionController in some cases will remove the presenting view controller’s views in IOS 7 iPad

When the UIDocumentInteractionController is dismissed, the presenting view controller’s views are removed, including elements from the UINavigationController.

The UIDocumentInteractionController dismisses and the presenting view controller’s views are removed, leaving a plain white/gray box where the presenting view controller formerly existed. The app no longer responds to any touch events after this point.

This Occurs on iPad Simulator (iOS 7.0) and iPad 3 (Wifi) running iOS 7 for Quick Look Pdf Reader.

Does not matter whether the application was compiled against the iOS 6.1 or iOS 7 SDK

Please let me know your suggestions.

Presenting and dismissing a modal view in ios 7

I have a view controller that has a button on it. The button is the Privacy Policy. When it’s clicked it goes to the proper IBAction and I create the privacy controller. – IBAction … { PrivacyPolic

iOS 7 – Getting warning message while presenting modal view controller

Compiling and running using iOS 7 – I am getting warning message: Presenting view controllers on detached view controllers is discouraged while presenting modal view controller. I never had problem

Dismissing Multiple View Controllers in iOS 5

In iOS 4, if you want to dismiss two nested modal view controllers, the following code works: [[[[self parentViewController] parentViewController] parentViewController] dismissModalViewControllerAnima

Apple’s controllers not presenting properly in iOS7

In my iOS app i present standerd controllers MFMessageComposeViewController and UIImagePickerController. But they both presenting with strange navigation bar. How can i fix this problem? UPD code f

UIDocumentInteractionController overlaps statusbar in iOS 7

I have an iPad app that I’m migrating to iOS 7. Most of the ‘issues’ with the statusbar have been solved but sadly one remains. When I open a PDF document using the UIDocumentInteractionController I g

iPad/iOS7: ‘Page’ modal view controller strange behaviour after presenting ‘Full screen’ view controller from it

My iPad application opens modal view controller with ‘Page’ presentation style. As you know ‘Page’ presentation style doesn’t cover status bar of presenting view controller to indicate page presentati

Presenting a modal view controller immediately after dismissing another

I’m dismissing a modal view controller and then immediately presenting another one, but the latter never happens. Here’s the code: [self dismissModalViewControllerAnimated:YES]; UIImagePickerControll

has Presenting modal view controller in iOS 4.3 for iPad changed?

Has Presenting modal view controller in iOS 4.3 for iPad changed? I created a new view application, then created a new UIViewControllerSubclass called One, I then changed the background of One.xib t

delegation issue with dismissing multiple view controllers

I asked a question about dismissing multiple view controllers previously and the answers that i was given along with the possible solutions i found elsewhere have all failed to achieve the desired eff

Problem dismissing multiple modal view controllers

I am having trouble getting my modal view controllers to display properly. I have a parent view controller that is the delegate for modal view A. In modal view A I am presenting modal view B, and havi

Answers

I have this same problem when presenting a UIDocumentInteractionController from a view controller presented as a modal form sheet on iPad in iOS 7 (worked fine in iOS 6).

It looks like that during the transition from the document interaction controller back to the presenting view controller, the presenting view controller’s view is wrapped in a temporary UITransitionView, and then that transition view is being removed from the view hierarchy after the transition is complete, along with the presenting view controller’s view, leaving just UIDropShadowView that is the backing view of the modal form sheet visible (the gray box).

I worked around the problem by keeping a reference to my presenting view controller’s root view (the one just before the drop shadow view in the hierarchy) when the document interaction controller preview will begin, and restoring that view to the hierarchy when the document interaction controller preview has ended.

Here’s sample code:

    - (void)documentInteractionControllerWillBeginPreview:(__unused UIDocumentInteractionController *)controller {

    if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
        // work around iOS 7 bug on ipad

        self.parentView = [[[self.view superview] superview] superview];
        self.containerView = [self.parentView superview];

        if (![[self.containerView superview] isKindOfClass: [UIWindow class]]) {
            // our assumption about the view hierarchy is broken, abort
            self.containerView = nil;
            self.parentView = nil;
        }
    }
}

    - (void)documentInteractionControllerDidEndPreview:(__unused UIDocumentInteractionController *)controller {

    if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
        if (!self.view.window && self.containerView) {
            assert(self.parentView);
            CGRect frame = self.parentView.frame;
            frame.origin = CGPointZero;
            self.parentView.frame = frame;
            [self.containerView addSubview: self.parentView];
            self.containerView = nil;
            self.parentView = nil;
        }
    }
}

I found Michael Kuntscher answer to be right on target. A slight modification is necessary if the UIDocumentInteractionController is presented from a popover.

There is a slight dependence on the view hierarchy that can be eliminated by iterating over the parent views until one with a UIWindow superview is found. In addition, I found that when a document interaction controller is presented from within a popover it is slightly different views that need to be stored as the parentView and containerView (specifically we want to find a containerView such that its superview is a UIPopoverView). The following snippet is a re-worked version of Michael’s answer to incorporate these changes (note that UIPopoverView is a private class, so we use string representations of the class rather than making a direct reference to each class):

- (void)documentInteractionControllerWillBeginPreview:(UIDocumentInteractionController *)controller {

    /* iOS 7 DIC bug workaround  */
    if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
        UIView *a_view = self.view;

        self.dicParentView = nil;
        self.dicContainerView = nil;

        while (a_view != nil) {
            UIView *super_super_view = [[a_view superview] superview];
            NSString *str_class = NSStringFromClass([super_super_view class]);

            if ([str_class isEqualToString:@"UIWindow"] ||
                [str_class hasSuffix:@"PopoverView"]) {
                self.dicParentView = a_view;
                self.dicContainerView = [a_view superview];
                break;
            }
            a_view = [a_view superview];
        }

        if (self.dicParentView == nil) {
            NSLog(@"Could not appropriate superview, unable to workaround DIC bug");
        }
    }
    /* end work around */
}

- (void)documentInteractionControllerDidEndPreview:(__unused UIDocumentInteractionController *)controller {
    /* iOS 7 DIC bug workaround */
    if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
        if ((self.view.window == nil) &&
            (self.dicContainerView != nil) &&
            (self.dicParentView != nil)) {
            NSLog(@"Restoring view for DIC presenter in the view hierarchy");
            CGRect frame = self.dicParentView.frame;
            frame.origin = CGPointZero;
            self.dicParentView.frame = frame;
            [self.dicContainerView addSubview: self.dicParentView];
            self.dicContainerView = nil;
            self.dicParentView = nil;
        }
    }
    /* end work around */
}

I had the exact same problem with the app stalling on a grey form sheet modal view that had lost all of its content after a UIDocumentInteractionController had been presented and dismissed. The two solutions here are great but I simplified them to cater for my particular case, which was a UINavigationController inside a form sheet modal that can present a PDF in the UIDocumentInteractionController, which I wanted to be full screen modal instead of pushed in the navigation controller because the form sheet area is too small for the PDF to be easily readable.

I implemented two UIDocumentInteractionControllerDelegate methods. Assume the following:

  • self.navController is a reference to the UINavigationController that is presented inside the form sheet modal.
  • there is a member variable declared in the UIViewController subclass @property (nonatomic, strong) UIView* docInteractionControllerWorkaroundSuperview;
  • SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO is a #define for ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

Firstly:

-(UIViewController*)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController*)controller
{    
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0") && self.navigationController.modalPresentationStyle == UIModalPresentationFormSheet)
    {
        self.docInteractionControllerWorkaroundSuperview = [self.navigationController.view superview];
    }
    return self.navigationController.visibleViewController;
}

then:

- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
{
    if (self.docInteractionControllerWorkaroundSuperview != nil)
    {
        NSLog(@"Workaround iOS 7 document interaction bug... resetting nav controller view into modal");

        //reset the nav controller view from whence it came.
        self.navigationController.view.frame = CGRectMake(0.0, 0.0, self.navigationController.view.frame.size.width, self.navigationController.view.frame.size.height);
        [self.docInteractionControllerWorkaroundSuperview addSubview:self.navigationController.view];

        self.docInteractionControllerWorkaroundSuperview = nil;
    }
}

i.e. when presenting the UIDocumentInteractionController, look at the superview of the navigation controller’s view. It works out to be a UIDropShadowView which I assume is the partially transparent grey/black background to the form sheet modal that dims out the view behind that presented the modal.

When the PDF has been dismissed, in documentInteractionControllerDidEndPreview the superview of the navigation controller’s view is now a UITransistionView. But then shortly after that (when the transition has completed), it gets set to nil. Somehow it got detached (or didn’t get re-attached) from the UIDropShadowView. By keeping a reference to view this when presenting the UIDocumentInteractionController, we can reattach it manually and everything works fine. Then be sure to nil out the reference to make sure we don’t accidentally retain it.

This method does not affect the behaviour on iOS 6 or any previous iOS versions.