Search code examples
iosobjective-cpresentviewcontrollerwkwebview

Long press leads to an error/warning when WKWebView tries to present a WKActionSheet


My view hierarchy looks like this:

  • (root) PRSBaseViewController - a UIViewController subclass - has child viewControllers
    • (presented) PRSModalWebViewController - a UINavigationController subclass
      • (pushed, animated:NO) PRSWebViewController - a UIViewController subclass - WKWebView is a subview.

When I try and long press on a link in the WebView I get the error:

Warning: Attempt to present <WKActionSheet: 0x127520d10> on <PRSBaseViewController: 0x1275117f0> whose view is not in the window hierarchy!

Instead of presenting the navigation using presentViewController:animated:completion and instead use the addChildViewController: dance to add it the view controller to the hierarchy. I get no errors, It's quite strange.

Does anyone know what could be causing the view hierarchy issues?

Update: I've made a Gist of all my classes


Solution

  • I have come across a similar behavior - and have not figured out how or why this occurs either.

    Here is my workaround. Since WKWebView is calling my RootViewController, I'm handling this by overriding RootViewController's presentViewController:animated:completion: - and if the RootViewController already has a presentedViewController, then it forwards the message to that controller. It seems to address the warning message, and gives me the long press menu when using WKWebView inside a modal view.

    - (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    
        // Unsure why WKWebView calls this controller - instead of it's own parent controller
        if (self.presentedViewController) {
            [self.presentedViewController presentViewController:viewControllerToPresent animated:flag completion:completion];
        } else {
            [super presentViewController:viewControllerToPresent animated:flag completion:completion];
        }
    }
    

    Or in swift:

    override func presentViewController(viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) {
        if presentedViewController != nil {
            // Unsure why WKWebView calls this controller - instead of it's own parent controller
            presentedViewController?.presentViewController(viewControllerToPresent, animated: flag, completion: completion)
        } else {
            super.presentViewController(viewControllerToPresent, animated: flag, completion: completion)
        }
    }