iOS 8 – 在设置关键窗口或关闭并立即呈现另一个视图控制器后快速呈现视图控制器时出现故障

Posted

技术标签:

【中文标题】iOS 8 – 在设置关键窗口或关闭并立即呈现另一个视图控制器后快速呈现视图控制器时出现故障【英文标题】:iOS 8 – Glitch when presenting view controller quickly after setting key window or dismissing and instanly presenting another 【发布时间】:2014-09-22 15:23:33 【问题描述】:

自从在 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];

或类似的东西。这解决了不平衡的调用问题,但视觉差距(rootviewcontroller、gap、presented one)变得(显然)更大。

当您将通常称为以下内容时,演示的缓慢性也很明显:

// 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 上执行直接转换,而无需可见的父视图控制器轻弹。现在,同样的事情 - 过渡期间的父轻弹,即使它都在没有动画的情况下处理。

有人会遇到这个问题吗?有什么解决办法吗?我很想解决这个问题,而无需使用UIWindows 为我需要完美传输的每一件事做一些搞笑的魔法。

【问题讨论】:

我也遇到了这个问题,但还没有找到解决办法。 您找到解决方案了吗? 也处理相同类型的问题。还没有解决办法。在我的代码中,iOS 7 运行良好,但 iOS 8 在关闭/呈现 viewController 组合之间有一个可怕的延迟。尝试将两个调用放在同一个动画块中无济于事。在没有动画的同一个调用中尝试了两者,仍然没有。 iOS 8 有很多隐藏的礼物...... 你们找到解决这个问题的办法了吗? 这是 iOS8 的 bug 吗? 【参考方案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 的使用没有要求或限制,所以这可能是部分方式,但这需要应用程序完全不同地实现——让我们假设使用一些窗口管理器和这些东西.但这通常是一个有点高级的流程。【参考方案2】:

如果你使用 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];

这里好像没有延迟。

【讨论】:

【参考方案3】:

由此解决了我从解雇/出席对中的延迟。它可能会或可能不会帮助您的实例。我不得不彻底改变我在 iOS 8 下显示/关闭模式视图控制器的策略:

[_rootViewController presentViewController:vc1 animated:NO completion:nil];

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

所以,一旦我稍后完成了 vc2,我会在同一个调用中同时关闭 vc1 和 vc2。这个策略也适用于 iOS 7。我也假设早期版本,但我没有测试它们。

【讨论】:

【参考方案4】:

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

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

【讨论】:

以上是关于iOS 8 – 在设置关键窗口或关闭并立即呈现另一个视图控制器后快速呈现视图控制器时出现故障的主要内容,如果未能解决你的问题,请参考以下文章

关闭一个自定义弹出窗口UIViewController并立即显示另一个自定义弹出窗口UIViewController -SWIFT

视图控制器不会立即关闭并呈现新的视图控制器

ios 在关闭前一个视图控制器后立即显示视图控制器

强制关闭报文“打开此链接?”的弹出窗口]]

如何在 iOS 8 中强制视图控制器方向?

OpenGL 窗口立即关闭并出现错误 -1073740777 (0xc0000417)