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!
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];
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?).
Related
dismissViewController method not working to get previous viewcontoller
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
popViewController work and go to previous viewcontroller
[self.navigationController popViewControllerAnimated:YES];
i want to pass data like below please help me.but as i describe dismissViewController method not working.
[self.navigationController dismissViewControllerAnimated:YES completion:^{
HomeVC *loading;
loading.IdNameLabel.text=display;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Code" message:display delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}];
thank in advance.
Update
-(void)viewWillAppear:(BOOL)animated{
self.IdNameLabel.text=self.GetscanResult;
}
this method contain in HomeVC.when dismiss navcontroller it shows HomeVC.
is upper method can call after dismiss viewcontroller?
SOLUTION
this is very stupid question when i am at beginner level.
here is specification about it.
it will depend on method which will you Present || Push viewController.
Delegate methods will work with protocol delegate method when view controller present.
The method you need to use to go back depends on how you showed the view controller.
The first of the two common ways are by using a navigation view controller to push and pop view controllers off the stack.
The other common way is to present and dismiss a view controller modally.
You cannot for example present a view controller modally, and expect to be able to pop it off from the navigation controller, or vice versa.
please help to understand the difficult situation.
I realized the Pop Up Window, the way has been described here
Then, in this window, I decided to implement a sample photo from the library, but when you open a new controller may receive the following warning:
Presenting view controllers on detached view controllers is discouraged <PopUpViewController: 0x7fbb405f4e90>.
The sample photo is implemented as follows:
picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
[picker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
[self presentViewController:picker animated:YES completion:nil];
try this:
[self.view.window.rootViewController presentViewController:picker animated:YES completion:nil];
I think you are presenting your picker in your viewDidAppear method.
If this is so, then that is the reason for the warning...
Please write another method that will present our picker and then perform it with delay.
[self performSelector:#selector(yourMethod)
withObject:nil afterDelay:0.0];
This will let your presentingController load completely before it presents another one.
I hope this helps..
EDIT
The problem is, you are presenting the picker, much before your action sheet is dismissed
EDIT 2
Also instead of actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex, use this method for getting clicked Index -
- actionSheet:didDismissWithButtonIndex:
Perhaps you need to add your popup window as a child controller using addChildController to the controller you show it from so that it is not detached from a view hierarchy?
Also you could try: Another option:
[self.parentViewController presentViewController:picker animated:YES completion:nil];
I noticed this on another thread as a solution. Warning :-Presenting view controllers on detached view controllers is discouraged
In your case, parentViewController may well be nil.
Edit After Seeing Code:
After looking at the code, the problem seems to be as follows:
1) The popup mechanism is using an instance of a UIViewController to create a layout, but you are not actually using the view controller at all. The popup mechanism (showInView:withImage:withMessage:animated:) is extracting the view from the controller and adding it into the view hierarchy of the controller asking for the popup. So using code from this popup controller instance which calls [self presentViewController...] is presenting a modal controller from a controller which is not actually being used. This is where the error is coming from I believe. You need to do all alerts and modal presentations from the original controller OR pass in the controller to use.
2) The original article mentions that because only the container view of the controller is used, you need to keep a strong reference to it when you create it. So you should have:
self.popViewController = [[PopUpViewController alloc] initWithNibName:#"PopUpViewController" bundle:nil];
Solution:
I would extend the showInView... method to pass in the controller which owns the view the popup is being spliced into. Then use this controller to present any modal controllers. So change:
- (void)showInView:(UIView *)aView withImage:(UIImage *)image withMessage:(NSString *)message animated:(BOOL)animated
to
- (void)showInController:(UIViewController *)aController inView:(UIView *)aView withImage:(UIImage *)image withMessage:(NSString *)message animated:(BOOL)animated
Store the controller reference passed in a property in your PopUpViewController class then use this property to call presentViewController...
I need to present a UIViewController as fullscreen (Above all other views). This UIViewController is currently inside a UINavigationController.
Is it possible to have the UINavigationController present it's current top UIViewController modally?
From within the UIViewController I would like to fullscreen, if I use:
[self.navigationController presentViewController:self animated:YES completion:nil]
Nothing seems to happen.. Is there a reason this is not allowed?
EDIT
I have posted another question in which I have solved this issue for every scenario. (Code snippet included there)
Is it possible for a UIViewController to present itself?
If you want to present a view controller modally, you should be presenting it from a different view controller. The modal presentation will show the presented view controller over the navigation controller (in fullscreen)
For instance,
UIViewController *firstVC = self;
UIViewController *secondVC = <the VC you want to present>
[firstVC presentViewController:secondVC animated:YES completion:nil]
Or just use a modal segue in Interface Builder.
You should use this :
[self presentViewController:self.navigationController animated:YES completion:nil];
to show a controller.
Assuming that the view controller you want to show modally is the navigation controllers top view controller
[self presentViewController:self.navigationController.topviewcontroller animated:YES completion:nil];
Hope this helps
How can to go back to previous view programmatically without UINavigationController, because all examples that I have found use UINavigationController ?
I am making view for sending feedback and I would like to use this view in many more apps.
If I use UINavigationController than app need to have UINavigationController to use my view for sending feedback.
Is this possible to do and how ?
This is code how I show my view for sending feedback:
- (IBAction)showFeedbackView:(id)sender {
WOC_FeedbackViewController *feedbackView = [[WOC_FeedbackViewController alloc] init];
[self presentViewController:feedbackView animated:YES completion:nil];
}
Use this to go back
[self dismissViewControllerAnimated:YES completion:nil];
Depending on what your project works (Storyboards or XIB) you can use presentViewController. But thats when you keep a reference on your last viewController's identifier.
If you know the ID of your viewController NSString *yourID;
1) Init your viewController
For storyboard
UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:yourID];
For XIB
UIViewController *vc = [UIViewController alloc]initWithNibName:yourID bundle:nil];
2) Presenting your ViewController
[self presentViewController:vc animated:YES completion:nil];
P.S This is a way to do this, but you should use navigationController because you can keep memory of a viewController on stack so when you need to access it again, you can access it faster. In other words, UINavigationController is applied in every iOS Application you see on App Store.
In Swift, you can use following line of code to go back to previous view controller without navigation controller:
self.dismissViewControllerAnimated(true, completion: nil)
I've got a view that I use for adding data into a table. I show this view using presentViewController:
AddViewController *avc = [self.storyboard instantiateViewControllerWithIdentifier:#"addview"];
[self presentViewController:avc animated:YES completion:nil];
This UINavigationController is the root view controller for a UIViewController that displays the add controls.
I trigger this UINavigationController from a couple of different places in my project and I'd like to have slightly different text for each. How can I interact with the UIViewController from where I call presentViewController, or otherwise change UIViewController depending on where it was invoked?
Ok, you can access the rootView controller of your navigation controller like this:
UINavigationController *yourNavigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"yourViewControllerID"];
YourRootController *yourRootController = (YourRootController*)[yourNavigationController topViewController];
yourRootController.someproperty = someValue
Than, just change some desired property in the view controller that you just get.
Please, tell me if it was something like this that you were looking for.
UIViewController *controller= (UIViewController)[self.navigationController subviews] count-2 ];
controller is the second-last view controller on the stack. which is the one that called add.
depending upon the value for [controler class] , you can set the text.