【问题标题】:Delay in presenting a modal view controller呈现模态视图控制器的延迟
【发布时间】:2014-10-20 15:25:20
【问题描述】:

我有一个基于标签栏的应用程序。所有 5 个选项卡中都有导航控制器,其中自定义视图控制器的实例正确设置为根视图控制器。这加载就好了。其中一些视图控制器包含表视图。当用户在表格视图中选择一行时,我想向用户显示一个模态视图控制器。 didSelectRowAtIndexPath 委托方法的(相关部分)如下所示:

SampleSelectorViewController *sampleVC = [[SampleSelectorViewController alloc] init];
[self presentViewController:sampleVC animated:YES completion:NULL];

模态视图控制器出现了,但它出现在一个非常明显的延迟之后。有时它甚至需要用户再次点击该行。我已经验证的几件事是:

  • 当用户点击行时,会调用表格视图的 didSelectRowAtIndexPath 方法
  • didSelectRowAtIndexPath 方法不包含任何阻塞调用。没有执行网络操作,模态视图控制器的设置不涉及任何处理密集型任务。它显示的数据是静态的。
  • 如果我将新的视图控制器推送到导航堆栈上(其他一切都保持不变),它的行为会非常完美,没有任何延迟。只有在模态呈现时才会遇到延迟。

有什么想法/建议吗?

【问题讨论】:

  • 出于兴趣,与animated:NO 一样慢吗?
  • 是的。动画似乎对这种奇怪的行为没有影响。
  • 有趣。我有同样的问题,即模式演示被延迟(或必须点击屏幕才能显示)。就我而言,它不是直接触发的,而是由 didSelectRowAtIndexPath 间接触发的。它调用一个委托方法,它调用一个委托方法,它以模态方式呈现。嗯..
  • 听起来与我的场景非常相似。你介意分享一下你是如何解决这个问题的吗?我之前或之后从未见过这个问题,并且项目中不再存在这种情况,所以我自己帮不上什么忙
  • 在 iOS 11、Xcode 9 上出现同样的问题,还没有运气......

标签: ios objective-c iphone modalviewcontroller


【解决方案1】:

似乎从tableView:didSelectRowAtIndexPath: 内部调用presentViewController:animated:completion 是有问题的。在 Instruments 中使用 Time Profiler 时,也很难找到任何突出的东西。有时我的模态视图会在不到一秒的时间内出现,而其他时候则需要 4 秒甚至 9 秒。

我认为它与底层的UIPresentationController 和布局有关,这是我在选择点击一行和在时间分析器中看到模式表示之间的时间区域时看到的少数几件事之一。

存在描述此问题的雷达:http://openradar.appspot.com/19563577

解决方法很简单,但并不令人满意:稍微延迟演示文稿以避免任何有争议的行为导致速度减慢。

dispatch_async(dispatch_get_main_queue(), ^{
   [self presentViewController:nav animated:YES completion:nil];
});

【讨论】:

  • 谢谢。你的修复对我有用,虽然我同意它有点不满意。
  • 感谢 azsromej 的回复。我有点卡在其他一些事情上。我会尽快验证修复并接受您的回答,如果它有效,但可能需要一段时间才能做到。
  • 在 dispatch_async 中包装演示代码对我有用,但这确实是一些疯狂的事情发生
  • 就像东说的那样,将演示代码包装在主线程上的异步调度调用中解决了这个问题。非常感谢您嗅出这个 azsromej! :)
【解决方案2】:

如果您在 tableView(:didSelectRowAt:) 中调用 present(:animated:completion:), selectionStyle == .none 用于选定的 tableview 单元格并且您遇到了这种奇怪的行为,然后尝试调用tableView.deselectRow(at:animated:) 在 tableView(_:didSelectRowAt:) 中的任何操作之前。

有帮助吗?

【讨论】:

  • 你能解释一下这种行为吗?有同样的。顺便说一句,解决方案已修复它。谢谢
【解决方案3】:

斯威夫特 4: 你可以使用如下。

DispatchQueue.main.async {
            let popUpVc = Utilities.viewController(name: "TwoBtnPopUpViewController", onStoryboard: "Login") as? TwoBtnPopUpViewController
            self.present(popUpVc!, animated: true, completion: nil)
        }

它对我有用。

【讨论】:

    【解决方案4】:

    我猜您还将单元格的 selectionStyle 设置为 UITableViewCellSelectionStyleNone。我改成UITableViewCellSelectionStyleDefault,效果很好。

    【讨论】:

      【解决方案5】:

      您应该从根 vc 模态显示它(例如:customTabBarRootViewController)。 保存引用,并使用引用控制器显示它。

      【讨论】:

      • 当你说 root vc 时,你的意思是我的窗口中的 root vc,在这种情况下它是我的标签栏控制器吗?另外,如果可能的话,我很想知道它的原因
      • 我不知道原因,我只知道它在运行由 xCode6.0.1 编译的 iOS7 的 iPhone 4 上毫无延迟地完美运行
      • 是的,我的意思是标签栏控制器,或持有它的控制器
      • 顺便说一句,如果显示的视图控制器上有“大量代码”,请尝试使用 dispatch dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //your heavy code here =) });
      • 我会尝试并在这里更新。新控制器中没有繁重的代码。这是一个简单的表格视图,有 5 个静态行供用户选择。
      【解决方案6】:

      当我从 tableView:didSelectRowAtIndexPath: 进行演示时,我也遇到了这种奇怪的延迟,看起来像是 Apple 错误。

      不过,这个解决方案似乎效果很好。

      CFRunLoopWakeUp(CFRunLoopGetCurrent()); // Fixes a bug where the main thread may be asleep, especially when using UITableViewCellSelectionStyleNone
      

      【讨论】:

        【解决方案7】:

        Swift 3中的解决方案

        在 SampleSelectorViewController(呈现的视图控制器)中使用下面的代码

        DispatchQueue.global(qos: .background).async {
        
        // Write your code
        
        }
        

        【讨论】:

        • 您需要在主队列中调度。所以使用:DispatchQueue.main.async { }
        【解决方案8】:

        这种行为的常见问题如下:

        为 tableView 中的单元格设置selectionStyle = .none(似乎它不依赖于UITableViewController 子类化,如http://openradar.appspot.com/19563577 所写)并在委托方法中使用

        override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
        

        动画取消选择

        tableView.deselectRow(at: indexPath, animated: true)
        

        这意味着非动画单元格的动画。

        在这种情况下,后续的视图控制器呈现会有延迟。

        有一些变通解决方案,包括主线程上的dispatch_async,但最好不要调用deselectRow,即使代码中的不可选择单元格上没有动画。

        【讨论】:

        • 我不再有权访问该代码库,因此我无法测试您的答案,但这听起来像是该线程上所有答案中最有希望的!
        【解决方案9】:

        根据@Y.Bonafons 的评论,在 Swift 中,您可以这样尝试,(适用于 Swift 4.x 和 5.0)

        DispatchQueue.main.async {
        
                        self.showAction() //Show what you need to present
                    }
        

        【讨论】:

          【解决方案10】:

          试试这个 对于 swift 5.2 版,您可以使用以下代码:

          DispatchQueue.main.async(execute:{self.present(nav, animated: true)})
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-02-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-15
            • 2011-06-21
            相关资源
            最近更新 更多