53

What does this error indicate:

"Popovers cannot be presented from a view which does not have a window."
MikeN
  • 45,039
  • 49
  • 151
  • 227
a111
  • 2,125
  • 5
  • 20
  • 21
  • 4
    This error also occurred, when it is passed nil to optionsButton in [optionsPopoverController presentPopoverFromBarButtonItem:optionsButton permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES]; – Mike Keskinov Dec 28 '11 at 19:04

13 Answers13

30

the thing that saved my life:

if (self.view.window != nil)
    [popoverController presentPopoverFromRect:CGRectMake(44, yCoord, 111, 111) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];

by adding if condition it doesn´t crash anymore. I don´t really get it because the presentPopoverFromRect function is ALWAYS called. There is no situation where window would be nil but anyway it did the trick.

edit: I have this code in viewDidAppear. Nevertheless in most cases it's enough to move presentPopoverFromRect to viewDidAppear or didMoveToWindow but in my case for some reason the if condition was necessary.

Mobile Developer
  • 5,730
  • 1
  • 39
  • 45
  • 1
    This solution is not really a solution. It only prevents the symptom from happening. You need to check when self.view is assigned to a window and then present the pop up. – Joris Weimar Nov 27 '11 at 03:23
  • actually it is the solution. The if condition is ALWAYS true no matter what. – Mobile Developer Nov 29 '11 at 16:30
  • it's not always true as i have debugged through code like this. if you think the if is always true, then why have the code? (to tricker a loadview?) – Joris Weimar Dec 07 '11 at 22:30
  • 8
    Actually, this did the trick for me too... I was so lost that a tried that solution and it saved my day. condition is alwais true if you test it, but not if you don't. !!! I believe that writing "self.view.window" just call a "moveToWindow" like method. – Vassily Dec 14 '11 at 18:20
  • If you reference self.view and it doesn't exist, the view is loaded, no? – z8000 Mar 02 '12 at 01:40
  • 3
    This actually the real answer for the above question. It should be marked as the correct one. – Robin Mar 22 '12 at 06:33
  • Well, at least for me, the if condition is always false no matter what. – shapecatcher Apr 12 '12 at 19:38
  • @shapecatcher You are right, and HardkorZLasu is completely wrong. What happens here is that self.view is nil if you call this code before the view is loaded. For me the solution was to move my code to viewDidAppear: (in the case you want to show a popOver at startup like I was trying to do) – Teofilo Israel Vizcaino Rodrig Jun 14 '12 at 14:29
  • I'm not wrong, man. I already had this code in viewDidAppear but it wasn't enough. If condition really solved it. Apparently other people had the same situation. Your case is probably different. – Mobile Developer Jun 14 '12 at 15:36
  • In my case the Window always reports as 'Nil'...How should I go ahead? – Jayprakash Dubey Feb 05 '14 at 10:00
24

the view you're adding the popover to has to already have been added to a window with the "addSubview:" method.

Try waiting until

- (void) didMoveToWindow

is called for the view and then load the popover

hey68you
  • 316
  • 3
  • 4
4

I got this problem.

I had a UITabBarController as the detail view, and I set the barButtonItem as the leftBarButtonItem on all three navigation controllers in the tab bar.

vcChart.navigationItem.leftBarButtonItem = barButtonItem;
vcAnalysis.navigationItem.leftBarButtonItem = barButtonItem;
vcTechnicals.navigationItem.leftBarButtonItem = barButtonItem;

Turns out only the last one added is valid, and the previous two would throw the exception when tapped on.

To fix it, I only set the leftBarButtonItem for the visible view controller, and just switched the barButtonItem to the visible view controller every time the user switched tabs.

Mobile Developer
  • 5,730
  • 1
  • 39
  • 45
  • 3
    Thanks! This help me figure out my problem. If anyone else is reading, just remove the barButtonItem from the other viewController before setting it to the current viewController. That should work. – sc45 May 13 '11 at 16:56
2

There are many ways to get to this error. Basically you need to wait to call the presentPopover command until your calling view is added to a window. I did it this way.

- (void)viewDidAppear:(BOOL)animated
{
    [self methodThatDisplaysPopOver];
}

My presentPopoverFromRect call is inside my methodThatDisplaysPopOver function.

You could protect every presentPopover call like MobiMaciek suggests with this.

if (self.view.window != nil)
    [popoverController presentPopoverFromRect:CGRectMake(10, 10, 100, 100) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];

However, I think it would be better to understand when self.view.window gets assigned and make sure that you present you popover after the view has a window.

Joshua Dance
  • 8,847
  • 4
  • 67
  • 72
2

Just encountered this issue. Turned out that the inView: parameter was using an IBOutlet that wasn't connected in IB. Thus, an attempt was made to launch the popover in nil. That doesn't work.

So, make sure you are using a valid view.

  • Similarly, I was setting inView to self.mySpecialView in a view controller where the view existed. Then I subclassed that view controller's class to use in a view controller where mySpecialView didn't exist and received this error. – arlomedia Aug 02 '12 at 19:13
1

yes, you are right but still we can add subview from parent class in it. so it can be represented from a view which have a window:

[popoverController.contentViewController.view addSubview:mySubView];
Steve
  • 1,022
  • 2
  • 9
  • 30
1

I received the same error message when assigning the same UIBarButtonItem to multiple navigation items as did Lewis. My example was slightly more complicated as I was using a UISplitViewController.

In my RootViewController I have an array of arrays to accomplish multiple sections within my table. Each time that the user clicks a row in the table, a new "detail" view controller is placed in the right pane of my splitViewController. Prior to setting the leftBarButtonItem = nil, I would receive a segfault after 3-4 clicks of the "Menu" button with the same error as a111. I updated my code to actually retrieve the previous detail view controller and set the leftBarButtonItem item to nil.

allData is my NSMutableArray that contains several other NSMutableArrays as objects.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    // Retrieve the new detail view controller
    UIViewController *detailViewController = [[self.allData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];

    // Add the detail view controller to a navigation controller and set the bar style
    UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
    detailNavigationController.navigationBar.barStyle = [[NSUserDefaults standardUserDefaults] integerForKey:@"UIBarStyle"];

    // Retrieve previous detail view controller and remove the leftBarButtonItem
    UINavigationController *previousDetailNavigationController = [splitViewController.viewControllers objectAtIndex:1];
    UIViewController *previousDetailViewController = [[previousDetailNavigationController viewControllers] lastObject];
    previousDetailViewController.navigationItem.leftBarButtonItem = nil;

    // Update the split view controller's view controllers array.
    NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailNavigationController, nil];
    splitViewController.viewControllers = viewControllers;

    [detailNavigationController release];
    [viewControllers release];

    // Dismiss the popover if it's present.
    if (popoverController != nil) {
        [popoverController dismissPopoverAnimated:YES];
    }

    // This sets the left bar to nil when in landscape and equal to "Menu" when in portrait.
    // We need to remove rootPopoverButtonItem from the previous viewController...
    detailViewController.navigationItem.leftBarButtonItem = rootPopoverButtonItem;
} 

The error message was slightly deceiving at first but the answers above helped me out. I wonder why I could click the "Menu" button up to 3-4 different times before the segfault... I'll investigate further.

TPoschel
  • 11
  • 1
1

This error also occurred when the inView: Parameter is incorrect - to test try self.view

John Goodstadt
  • 678
  • 8
  • 13
0

I had the same error message as the OP, in a very similar situation to that reported by TPoschel, except I had a split view controller with an embedded tab bar controller in the detail pane, and a navigation controller within this. The bar button item is added as the navigation bar leftBarButtonItem.

Only on iOS5.0 (not 5.1) does it seem to require you invalidate the bar button item on the tab bar you are leaving by setting it to nil. Before then adding the bar button to the navigation bar on the tab you are going to.

If I don't do that, from debugging my own code, the window property of the bar button item stays set to nil, and causes the exception, on returning to a screen you'd previously been to. I'm guessing as a side effect of setting the leftBarButtonItem in the navigation item, it goes off and sets the frame. But it doesn't seem to bother unless the button is different from what is currently set there. Hence, the need to set it to nil when leaving a tab, even though it is technically the same button that's being passed around.

I would upvote TPoschel's answer, except SO won't let me.

Rob Glassey
  • 2,237
  • 20
  • 21
0

I had a problem like this. Received this message when clicking a customized UIBarButton item that invoked a selector method with did performSeque.

The problem was my segue was still attached to the UIBarButton item. It should have been attached to the main view of of the view controller. Changed this and worked fine.

P.S., all this got started because I wanted to add and "info" button to my UIToolBar. This isn't one in the system provided list and should be.

The iOSDev
  • 5,237
  • 7
  • 41
  • 78
caprijoe
  • 1
  • 1
0

There will be a view from which you asks to display your popover.The reason for this error is because you didn't made this view as a subview of the window.

 [self.view addSubview:displayPopOverVC];

where displayPopOverVC is the view controller from which the popOver appears

MouzmiSadiq
  • 2,069
  • 3
  • 18
  • 21
0

i had the same problem, after adding PresentPopOver in viewDidAppear this was solved

- (void) viewDidAppear:(BOOL)animated{
     CGRect popoverRect = screenBounds;         
     popoverRect.size.width = MIN(popoverRect.size.width,0) ;
     popoverRect.origin.x  = screenBounds.origin.x;

     [popoverController
     presentPopoverFromRect:popoverRect
     inView:self.view
     permittedArrowDirections:UIPopoverArrowDirectionAny
     animated:YES];
}

this was happening as inView:self.view should be called after viewDidLoad as suggested by @hey68You and MobiMaciek..

iMeMyself
  • 1,649
  • 13
  • 28
0

I replaced

[actionSheet showFromBarButtonItem:self.navigationController.navigationItem.leftBarButtonItem animated:YES];

with

[actionSheet showInView:self.view];
Rose Perrone
  • 61,572
  • 58
  • 208
  • 243