Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Whose view is not in the window hierarchy issue?

Warning: Attempt to present on whose view is not in the window hierarchy!

Yes I have looked at the other questions and answers before posting this question. They have not helped me resolve this. Here's what I am doing. I am calling on my singleton class socialHelper to display an action sheet, where postToFacebook method is an option to select. When clicking on this action, I get the Warning above and the postToFacebook is not displayed. I'm calling this from a UIViewController with the UINavigationController as the main controller, and my SocialHelper class is a NSOject.

- (void)postToFacebook
{
    if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {

    slComposeViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
    [slComposeViewController setInitialText:@"Building stairs? Checkout StairsPro on the app store!"];
    [slComposeViewController addImage:[UIImage imageNamed:@"StairsIcon120x120.png"]];
    [slComposeViewController addURL:[NSURL URLWithString:@"https://itunes.apple.com/us/app/stairs-pro/id477032819?ls=1&mt=8"]];

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

    // I've also tried this, which shows the post window, but after hitting cancel or post, my previous viewController is not the current viewController. So my navigation bar is gone and can't move around in my app. 
    // [[[[UIApplication sharedApplication]delegate]window]setRootViewController:slComposeViewController];

    }else{
        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"No Facebook Account" message:@"No Facebook account has been configured. You can configure or create a Facebook account in settings." delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
        [alert show];
}
}

So what I'm asking is what is the best way to get the slComposerViewController to display in this case, also how we could use the UIApplication option as well. Thank you!

like image 908
Jason Avatar asked May 31 '14 14:05

Jason


2 Answers

I would change the method to pass in the ViewController to make sure the correct VC is presenting it like so:

- (void)postToFacebookFromVC:(UIViewController*) presentingVC

And inside that method when calling presentViewController use:

[presentingVC presentViewController:slComposeViewController animated:YES completion:nil];

I assume then that using your socialHelper singleton class would be something like:

[[socialHelper sharedResource] postToFacebookFromVC:self]; //inside the VC that you want to display it

For your second question on using the rootViewController try this:

[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:slComposeViewController animated:YES completion:nil];

Edit: Since the first two suggestions didn't work for your project, try getting the topMost ViewController and presenting slComposeViewController from it instead of "self" like so:

UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (topController.presentedViewController) {
    topController = topController.presentedViewController;
}

[topController presentViewController:slComposeViewController animated:YES completion:nil];
like image 184
rymagno Avatar answered Oct 16 '22 23:10

rymagno


This answer won't resolve your issue but it should make some sense of why it isn't working and help you towards finding the right solution for what you originally intended.

SLComposeViewController being a UIViewController has an associated UIView that will be displayed on top of the view of the controller receiving the message presentViewController.

As correctly done in this line but, self needs to be a UIViewController (an object that has a view property).

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

It will work if you move your -postToFaceBook method out of the SocialHelper class and put it inside your UIViewController class (file) that will display the action sheet, so that way self is actually a UIViewController instead of NSObject.

From Apple's UIViewController reference page:

When you call the presentViewController method on a UIViewController it sets the presentedViewController property to the specified view controller, resizes that view controller’s view and then adds the view to the view hierarchy.

Your SocialHelper class is not a view controller so it does not have a view to which the action sheet view could be added to display it (on top).

I'm thinking even if you inherit your SocialHelper from UIViewController, the view of your SocialHelper would not be in your controller's view hierarchy.

If it is only two or three view controllers where you need to display the action sheet, I would replicate the code instead of creating a separate class; if it is several view controllers, then it makes sense to have the action sheet display logic as a separate class, you just need to find the right design pattern to do that.

Edit 1

Forgot to mention the declaration of your variable is missing the SLComposeViewController *

Is it just missing in your post or you have declared the variable somewhere else in your viewcontroller class?

Try declaring it right there in the same line you create the SLComposeViewController; that might fix the issue. If that did not work then double-check all you need to do to support Facebook in your app by looking at this very simple and easy to follow tutorial.

SLComposeViewController *slComposeViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];

I'm assuming you created your navigation controller with main view controller as its root:

navigationController = [[UINavigationController alloc] initWithRootViewController:mainViewController];

And to show the flip side controller you do this in your main view controller:

[[self navigationController] pushViewController:flipSideViewController animated:NO];

The flip side controller has the about button to show the about view when tapped; I'm thinking you do a presentViewController not a push:

[self presentViewController:aboutViewController animated:YES];

Finally, in the about view controller you should have your -postToFacebook method with the corrected line mentioned above; which will be called by the log (button?).

like image 28
Only You Avatar answered Oct 17 '22 00:10

Only You