<UITabBarController: 0x197870>的开始/结束出现转换调用不平衡。

133

我在SO上阅读到另一个用户遇到类似的错误,但这个错误和那个不同。

当我最初添加一个视图控制器时,我收到了这个消息:

Unbalanced calls to begin/end appearance transitions for 
<UITabBarController: 0x197870>

应用程序的结构如下:

我使用了一个包含5个视图控制器的标签栏控制器。在初始显示标签中,我调用一个新的视图控制器作为应用程序的介绍。

我使用以下代码来调用介绍视图控制器:

IntroVC *vc = [[IntroVC alloc] init];
[self presentModalViewController:vc animated:YES];
[vc release]; 

在这个IntroVC视图控制器显示之后,出现了上述错误。

p.s. 我正在使用xCode 4.2&iOS 5.0 SDK,开发iOS 4.3应用程序。


嗨,Shivan,我和你有同样的问题。但是在查看下面的答案后,我仍然无法解决它。请问你在哪里调用了介绍视图控制器? - ZYiOS
24个回答

98

没有看到更多周围的代码,我不能给出明确的答案,但我有两个理论。

  1. 你没有使用 UIViewController指定初始化程序 initWithNibName:bundle:。尝试使用它而不仅仅是 init

  2. 此外,self 可能是选项卡栏控制器的一个视图控制器。总是从最上层的视图控制器呈现视图控制器,这意味着在这种情况下,请请求选项卡栏控制器代表视图控制器呈现覆盖视图控制器。您仍然可以将任何回调委托给真正的视图控制器,但必须要求选项卡栏控制器进行呈现和关闭。


2
#1 对我来说解决了这个问题,我使用的是initWithNibName:nil bundle:nil而不是init。 - Hua-Ying
179
如果在应用程序初始化完成之前,呈现模态视图控制器,就会出现此警告。例如,在使用选项卡应用程序模板的应用程序中,将 modal vc 呈现在 application:didFinishLaunching 的最后一行,并放在 self.tabBarController 上方。这时会出现警告。解决方法是先让堆栈解除,然后在另一个方法中使用 performSelector withDelay:0.0 调用呈现模态 vc。 - danh
10
这里有另一个问题解释了为什么performSelector withDelay函数会起作用。https://dev59.com/FHI-5IYBdhLWcg3wTWdu - fatih
2
danh的解决方案对我有用,但我必须使用0.1而不是0.0。 - Brandon O'Rourke
11
与其使用 performSelectorWithDelay 为零,不如在 viewDidAppear 中执行此操作,而不是在 viewDidLoad 或其他地方执行。 - tooluser
显示剩余2条评论

40

我通过将animated从YES更改为NO来解决了这个错误。

来自:

[tabBarController presentModalViewController:viewController animated:YES];

发送至:

[tabBarController presentModalViewController:viewController animated:NO];

4
如果您不关心动画,这将解决问题,但如果您需要animated:YES,则尝试danh在被接受的答案上的评论:https://dev59.com/Omsz5IYBdhLWcg3wcnhb#ZqGdEYcBWogLw_1bkULv - wxactly
3
FYI: presentModalViewController:animated: 在 iOS6 中已经被弃用。 - Z S
如果我将动画从“否”更改为“是”,它就解决了我的问题... 嗯。 - Eric

16

danh 发布:

如果在应用程序完成初始化之前显示模态 VC,将会出现此警告。例如,在标签式应用程序模板应用程序中启动一个并在 application:didFinishLaunching 的最后一行上方呈现模态 vc。警告出现。解决方法:先让堆栈展开,然后在另一个使用 performSelector withDelay:0.0 调用的方法中呈现模态 vc。

尝试将该方法移入 viewWillAppear 中,并加以保护,以确保其仅被执行一次(建议设置属性)。


为什么使用viewWillAppear而不是viewDidAppear - CyberMew

7

对于许多情况,另一种解决方案是确保在不适合的过程(如初始化期间)完成后,转换 UIViewController 之间的转换发生,方法如下:

__weak MyViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf presentViewController:vc animated:YES];
});

这同样适用于pushViewController:animated:等操作。

4

我曾经遇到过同样的问题。在我的第一个UIViewController中,在viewDidLoad中调用了一个方法。

- (void)viewDidLoad{
    [super viewDidLoad];

    [self performSelector:@selector(loadingView)
               withObject:nil afterDelay:0.5];
}

- (void)loadingView{

    [self performSegueWithIdentifier:@"loadedData" sender:self];
}

在第二个 UIViewController 中,我也使用了0.5秒的延迟进行相同的操作。将延迟时间增加后,它可以正常工作。就像一个segue不能在另一个segue之后太快执行一样。


7
为了实现这个目的,提供了视图生命周期方法viewDidAppear,比引入人为延迟更可靠。顺便说一句,这种方法会更好。 - tooluser
1
这是正确的答案,除了延迟为0足以等待导航控制器准备好进行新的导航。 - malhal
完全正确,你必须在 viewDidAppear 中调用它,这样 UINavigationController 才准备好处理它。我将我的帖子更改为此 ;) - Alex Cio
我觉得这应该移动到viewWillAppear,这样你就不用担心视图是否初始化了。 - horsejockey

3

我遇到了这个问题,是因为打错了字:

override func viewDidAppear(animated: Bool) {
    super.viewWillAppear(animated)

代替
override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

它调用了父类的 "WillAppear" 而不是 "DidAppear"。

3
如果你在使用 `transitioningDelegate`(不是本问题的示例情况),还需要将 `modalPresentationStyle` 设置为 `.Custom`。
Swift
let vc = storyboard.instantiateViewControllerWithIdentifier("...")
vc.transitioningDelegate = self
vc.modalPresentationStyle = .Custom

3

当我需要从另一个视图控制器中呈现我的登录视图控制器时,如果用户没有授权,我遇到了同样的问题。我在另一个视图控制器的ViewDidLoad方法中解决了这个问题(如果未经授权,则presentModalViewController)。当我开始在ViewDidAppear方法中执行它时,我解决了这个问题。我认为ViewDidLoad仅初始化属性,之后实际显示视图算法开始!这就是为什么您必须使用viewDidAppear方法进行模态转换的原因!


2
我通过编写代码解决了这个问题。
[self.navigationController presentViewController:viewController 
                                        animated:TRUE 
                                      completion:NULL];

3
建议使用更习惯用语且更安全的方式:animated:YES completion:nil - powerj1984
2
我可以给你更多的惯用语,但这样更安全吗? - Zev Eisenberg

2

我曾遇到过同样的问题,通过以下方法解决:

  1. 使用故事板的instantiateViewControllerWithIdentifier方法初始化ViewController。例如:Intro *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"introVC"];
  2. [self.tabBarController presentModalViewController : vc animated:YES];

故事板中已经存在了我的viewcontroller,在我的情况下只使用[[introvc alloc] init];无效。


1
很高兴看到您使用新的Storyboard功能。但是在我的情况下,我并没有使用Storyboard... - Raptor
我只是想指出,“instantiateViewControllerWithIdentifier”需要控制器的标识符。更多细节请查看https://dev59.com/Emsy5IYBdhLWcg3w-zB4。 - Kishor Kundan

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