iOS 8 - 设置关键窗口或解除绑定后快速呈现视图控制器时出现故障,立即呈现另一个视图控制器。

13

在测试我的应用程序在iOS 8上时,我发现绕过视图控制器的初始化和呈现非常缓慢。

我曾经在iOS 6和7上使用类似于以下代码的代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ....

    [self.window setRootViewController:_rootController];
    [self.window makeKeyAndVisible];

    // Conditions

    if (#first launch condition#) {
        // quite small controller containing Welcome showcase
        WelcomeViewController *w = ....
        [_rootViewController presentViewController:w animated:NO];
    }

    else if (#last opened item condition#) {
        // pretty big container, root view controller contains
        // a grid view which opens Item detail container the same way
        ItemDetailController *item = ....
        [_rootViewController presentViewController:item animated:NO];
    }

}

这在 iOS 8 上变得非常缓慢。根视图控制器现在出现可见,但会立即重新绘制屏幕以显示呈现的内容,这需要0.5-1秒的时间。此外,演示速度的缓慢导致出现“Unbalanced calls to begin/end appearance transitions _rootViewController”警告。

最初的快速提示是将调用两个条件的函数移动到另一个函数中,并使用零延迟调用它,以便在下一个主运行循环中处理:

[self performSelector:@selector(postAppFinishedPresentation) withObject:nil afterDelay:0];

或者类似的东西。这解决了不平衡的调用问题,但是视觉间隙(根视图控制器、间隙、呈现的视图控制器)变得更大了(显然)。

当你调用像这样的常规内容时,演示的缓慢也很明显:

// Example: Delegate caught finished Sign In dialog,
//          dismiss it and instantly switch to Profile controller

-(void)signInViewControllerDidFinishedSuccessfully
{
    [self dismissViewControllerAnimated:NO completion:^{
         UserProfileViewController *userProfile = ...
         [self presentViewController:userProfile animated:NO];
    }];
}
应该有一段完全公平的代码,用于在iOS 7上执行无显式闪烁的直接转换。现在,同样的事情 - 即使没有动画处理,父级在过渡期间也会闪烁。
有人遇到这个问题吗?有解决方案吗?我希望能够解决这个问题,而不需要对我需要无缝转换的每个东西都进行一些有趣的魔法操作,例如UIWindow。

我也遇到了这个问题,但是还没有找到解决方案。 - Ben Gotow
你找到解决方案了吗? - Jason Whitehorn
同样遇到了相同的问题,目前还没有解决方案。在我的代码中,iOS 7 运行得非常好,但是 iOS 8 在 dismiss/present viewController 组合之间有一个可怕的延迟。尝试将两个调用放在同一个动画块中,但无济于事。尝试在同一个调用中使用无动画,仍然没有效果。iOS 8 有很多隐藏的“礼物”... - Eclectic DNA
你们有没有找到解决这个问题的办法? - DevCali
这是iOS8的一个错误吗? - Aaron
你尝试过将条件部分移动到RootViewController的viewDidAppear中吗(并添加一些逻辑以防止它们多次呈现)? - James Chen
4个回答

1
我不确定需求是否限制为必须有根视图控制器并在其上呈现任何内容。
但是根据您的代码,它具有欢迎视图控制器,我认为在这种情况下,这种逻辑更有用。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Conditions

    if (#first launch condition#) {
        // quite small controller containing Welcome showcase
        WelcomeViewController *w = ....

        //It can be navigation or tab bar controller which have "w" as rootviewcontroller
        [self.window setRootViewController:w];
    }

    else if (#last opened item condition#) {
        // pretty big container, root view controller contains
        // a grid view which opens Item detail container the same way
        ItemDetailController *item = ....
        //It can be navigation or tab bar controller which have "item" as rootviewcontroller
        [self.window setRootViewController:item];
    }

    [self.window makeKeyAndVisible];

}

好的,UIWindow 的使用没有要求或限制,所以这可能部分是一种方式,但这需要完全不同的应用程序实现方式——假设使用某些窗口管理器等等。但这通常是一种较为高级的流程。 - Michi

0

在iOS8中,我发现旧的演示在完成块中还没有完全完成,立即调用dismiss或present可能会导致控制台消息,并且有时甚至不会发生present/dismiss。通过向第二个演示添加进一步延迟执行,我已经取得了一些成功:

 [self dismissViewControllerAnimated:NO completion:^{
         UserProfileViewController *userProfile = ...
         [[NSOperationQueue mainQueue] addOperationWithBlock:^{
             [self presentViewController:userProfile animated:NO];
         }];
    }];

0
这个问题是由于关闭/呈现视图控制器成对出现时导致的延迟,通过这个方法得以解决。也许可以帮到你的情况。我必须完全改变我的策略,在iOS 8下显示/关闭模态视图控制器:
[_rootViewController presentViewController:vc1 animated:NO completion:nil];

if(iNeedToDisplayVC2) {
     [vc1 presentViewController:vc2 animated:NO completion:nil];
}

所以,一旦我结束 vc2 后,我可以在同一个调用中解除掉 vc1 和 vc2。这种策略同样适用于 iOS 7。我认为之前的版本也是如此,但我没有测试过。

0

如果您使用Storyboard,为什么不尝试:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:@"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];
ViewController *_rootController = [storyboard instantiateViewControllerWithIdentifier:@"root"];
[self.window setRootViewController:_rootController];
[self.window makeKeyAndVisible];
if (vcToShow == 1) {
     ViewController2 *w = [storyboard instantiateViewControllerWithIdentifier:@"vc2"];
    [_rootController presentViewController:w animated:NO completion:nil];
}
else if (vcToShow == 2) {
    ViewController2 *w = [storyboard instantiateViewControllerWithIdentifier:@"vc3"];
    [_rootController presentViewController:w animated:NO completion:nil];
}

看起来这里没有延迟。


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