弹出窗口无法从没有窗口的视图中呈现

53
这个错误提示的含义是:“不能在没有窗口的视图中显示弹出框(popovers)”。

4
当在[optionsPopoverController presentPopoverFromBarButtonItem:optionsButton permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];中传递nil给optionsButton时,也会发生此错误。 - Mike Keskinov
13个回答

30

拯救我生命的东西:

if (self.view.window != nil)
    [popoverController presentPopoverFromRect:CGRectMake(44, yCoord, 111, 111) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
通过添加if条件,它不会再崩溃了。我真的不太明白,因为presentPopoverFromRect函数总是被调用。没有窗口为空的情况,但这样做有帮助。

编辑:我在viewDidAppear中有这段代码。大多数情况下,将presentPopoverFromRect移动到viewDidAppeardidMoveToWindow就足够了,但在我的情况下,if条件是必要的。


1
这个解决方案并不是真正的解决方案。它只是防止症状发生。您需要检查当self.view被分配给一个窗口时,然后再呈现弹出窗口。 - Joris Weimar
实际上这就是解决方案。无论如何,if条件语句始终为真。 - Mobile Developer
8
实际上,这个方法对我也起了作用……我当时很迷茫,尝试了这个解决方案后,它拯救了我的一天。如果你进行测试,条件始终为真,但如果不进行测试,则条件不成立。!!! 我相信编写“self.view.window”只是调用了一个类似于“moveToWindow”的方法。 - Vassily
3
这实际上是以上问题的真正答案,应该将其标记为正确答案。 - Robin
在我的情况下,窗口始终报告为“Nil”...我该怎么办? - Jayprakash Dubey
显示剩余5条评论

24

要添加弹出窗口的视图必须使用“addSubview:”方法已经添加到窗口中。

尝试等待直到视图被添加到窗口中再添加弹出窗口。

- (void) didMoveToWindow

调用该视图,然后加载弹出窗口。


18
你能够解释一下吗?我不明白。 - thndrkiss
2
只需将[popoverController presentPopoverFromRect...]放在didMoveToWindow或viewDidAppear函数中即可。它会在viewDidLoad之后被调用。 - Mobile Developer
1
UIBarButtonItem怎么样? - jjxtra

4

我遇到了这个问题。

我有一个UITabBarController作为详细视图,并将barButtonItem设置为选项卡栏中三个导航控制器的leftBarButtonItem。

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

原来只有最后一个添加的有效,之前的两个在点击时会抛出异常。
为了解决这个问题,我只为可见的视图控制器设置了leftBarButtonItem,并且每次用户切换标签时只切换barButtonItem到可见的视图控制器。

3
谢谢!这帮助我解决了我的问题。如果其他人也在阅读,请在将其设置为当前视图控制器之前从另一个视图控制器中移除barButtonItem,那应该就可以解决问题了。 - sc45

2

有很多方法可以导致这个错误。基本上,您需要等待调用presentPopover命令,直到您的调用视图已添加到窗口中。我是这样做的。

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

我的presentPopoverFromRect调用在我的methodThatDisplaysPopOver函数内。

您可以像MobiMaciek建议的那样保护每个presentPopover调用,使用以下代码:

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

然而,我认为更好的方式是了解何时赋值self.view.window并确保在视图拥有窗口后再展示弹出视图。


2

刚遇到了这个问题。事实证明,inView:参数在IB中没有连接的IBOutlet被使用了。因此,试图在nil中启动弹出窗口是不起作用的。

所以,请确保您正在使用有效的视图。


同样地,我在一个存在该视图的视图控制器中将inView设置为self.mySpecialView。然后,我对该视图控制器的类进行了子类化,以在一个不存在mySpecialView的视图控制器中使用,并收到了这个错误。 - arlomedia

1

当我像Lewis一样将同一个UIBarButtonItem分配给多个导航项时,我收到了相同的错误消息。我的示例稍微复杂一些,因为我正在使用UISplitViewController

在我的RootViewController中,我有一个数组的数组来完成表格中的多个部分。每次用户单击表格中的行时,新的“详细”视图控制器就会放置在我的splitViewController的右窗格中。在设置leftBarButtonItem = nil之前,如果我点击“菜单”按钮3-4次,我会收到与a111相同的错误,并且程序会崩溃。我更新了我的代码,实际上检索了以前的详细视图控制器并将leftBarButtonItem项目设置为nil。

allData是我的NSMutableArray,其中包含几个其他NSMutableArrays作为对象。

- (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;
} 

一开始错误信息有点误导人,但上面的答案帮了我很多。我想知道为什么在段错误之前我可以点击“菜单”按钮3-4次不同的次数...我会进一步调查。


1

是的,你说得对,但我们仍然可以从父类中添加子视图。因此,它可以表示为一个具有窗口的视图:

[popoverController.contentViewController.view addSubview:mySubView];

1

当inView参数不正确时,也会出现此错误 - 请尝试使用self.view进行测试


0
我曾经遇到过同样的问题,在 viewDidAppear 中添加 PresentPopOver 后,问题得以解决。
- (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];
}

这是由于@hey68You和MobiMaciek建议在viewDidLoad之后调用inView:self.view。


0

我替换了

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

使用

[actionSheet showInView:self.view];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接