iOS应用程序在PushViewController上冻结

我的导航控制器间歇性地冻结推。 它似乎将新的视图控制器添加到堆栈,但animation永远不会发生。 我还有两个容器可以在屏幕上保存视图控制器,在导航控制器冻结之后,我可以很好地与它们交互。 真正有趣的是,如果我尝试将另一个视图控制器推到导航控制器的堆栈上,我注意到堆栈顶部有一个额外的视图控制器(我最初推送的视图控制器冻结了导航控制器)。 因此,如果我在主屏幕上(我们将它称为VC-Home),并尝试推新视图(VC-1)并冻结,则尝试推新视图(VC-2)这是我在推送之前在当前堆栈中看到的内容:

{ [VC-Home, VC-1] }

和pushViewController被调用后,它保持不变; VC-2不被添加到堆栈。

从我所知道的情况来看,导航控制器通过在animation开始之前使以前的视图控制器处于非活动状态来启动animation,但是animation从未发生,导致导航控制器处于冻结状态。

我通过调用UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController")从故事板创build新的视图控制器,所以我不认为这里有任何问题。 我也没有重写导航栏上的pushViewController。 关于我的应用程序的一些独特的事情是它是非常高分辨率的图像沉重(使用SDWebImage来pipe理),我一次总是有三个容器在屏幕上(一个导航控制器,一个视图控制器search,一个交互式阴沟/侧面/滑出菜单)。

CPU使用率低,内存使用情况正常(发生冻结时稳定在60-70MB左右)。

有什么想法可能会导致这个或任何debugging技巧,可以帮助我发现真正的问题?

更新

没有唯一的代码UINavigationController,因为我只是推pushViewController()。 这是调用它的代码:

 func didSelectItem(profile: SimpleProfile) { let vc = UIStoryboard.profileViewController() vc.profile = profile navigationController?.pushViewController(vc, animated: true) } 

我推送的ViewController在viewDidLoad中有以下代码:

 override func viewDidLoad() { super.viewDidLoad() button.roundView() if let type = profile?.profileType { //load multiple view controllers into a view pager based on type let viewControllers = ProfileTypeTabAdapter.produceViewControllersBasedOnType(type) loadViewPagerViews(viewControllers) let topInset = headerView.bounds.height + tabScrollView.contentSize.height if let viewPager = viewPager { for view in viewPager.views { if let tempView = view as? PagingChildViewController { tempView.profile = fullProfile tempView.parentVCDelegate = self tempView.topInset = topInset } } } } } func loadViewPagerViews(viewControllers: [UIViewController]) { viewPager?.views = viewControllers viewPager?.delegate = self //loading views into paging scroll view (using PureLayout to create constraints) let _ = subviews.map { $0.removeFromSuperview() } var i = 0 for item in views { addSubview(item.view) item.view.autoSetDimensionsToSize(CGSize(width: tabWidth, height: tabHeight)) if i == 0 { item.view.autoPinEdgeToSuperviewEdge(.Leading) } else if let previousView = views[i-1].view { item.view.autoPinEdge(.Leading, toEdge: .Trailing, ofView: previousView) } if i == views.count { item.view.autoPinEdgeToSuperviewEdge(.Trailing) } i += 1 } contentSize = CGSize(width: Double(i)*Double(tabWidth), height: Double(tabHeight)) } 

更新2

我终于把它冻结了。 该应用程序在后台,我把它拿回来,试图推动一个视图控制器,当它冻结的堆栈。 我注意到一个animation正在发生。 我在页面顶部有一个滚动视图,每10秒钟浏览其内容(想想app store的顶部横幅)。 在这个冻结,我注意到这个横幅是中间animation。

这是从我的UIScrollView每10秒被调用的滚动function:

 func moveToNextItem() { let pageWidth: CGFloat = CGRectGetWidth(frame) let maxWidth: CGFloat = pageWidth * CGFloat(max(images.count, profileImages.count)) let contentOffset: CGFloat = self.contentOffset.x let slideToX = contentOffset + pageWidth //if this is the end of the line, stop the timer if contentOffset + pageWidth == maxWidth { timer?.invalidate() timer = nil return } scrollRectToVisible(CGRectMake(slideToX, 0, pageWidth, CGRectGetHeight(frame)), animated: true) } 

我不记得因为有animation/卷轴而停下来,但是我可能是错的。

我也重新检查了堆栈,如上所述的情况同样是[VC-Home,VC-1]是堆栈,VC-2没有被压入。 我也经历了VC-1的variables,一切都已经加载(数据调用和图像加载)。

更新3

这是第二个越来越陌生。 我已经覆盖pushViewController,所以我可以在那里放置一个断点,并根据Alessandro Ornano的反应做一些debugging。 如果我推视图控制器失败,然后发送我的应用程序的背景,把一个断点到pushViewController调用,并将应用程序回来,断点立即打了很多次。 如果我继续过去所有的命中,下一个视图控制器突然变得可见,我试图推动的最后一个视图控制器现在在堆栈上作为最后一个视图控制器。 这意味着我所看到的那个人仍然残疾,这基本上使我处于和以前一样的地位。

几周前我们遇到了同样的问题。 而对于我们的问题,我们把它缩小到left-edge pop gesture recogniser 。 您可以尝试使用以下步骤检查是否可以重现此问题

  • 当它下面没有视图控制器时(例如,在根视图控制器,你的VC-Home控制器上),尝试使用左边的popup手势,
  • 尝试之后点击任何UI元素。

如果您能够重现冻结,请尝试在视图控制器堆栈只有一个视图控制器时禁用interactivePopGestureRecognizer

参考这个问题了解更多细节。 以下是链接中的代码,以方便参考。

 - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { if (self.viewControllers.count > 1) { self.interactivePopGestureRecognizer.enabled = YES; } else { self.interactivePopGestureRecognizer.enabled = NO; } } } 

@Penkey Suresh很好的回答 ! 保存了我的一天! 以下是SWIFT 3版本,其中有一小部分对我有所帮助:

  func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { if (navigationController.viewControllers.count > 1) { self.navigationController?.interactivePopGestureRecognizer?.delegate = self navigationController.interactivePopGestureRecognizer?.isEnabled = true; } else { self.navigationController?.interactivePopGestureRecognizer?.delegate = nil navigationController.interactivePopGestureRecognizer?.isEnabled = false; } } 

只要不要忘记添加UINavigationControllerDelegate并设置navigationController?.delegate = self另一个重要的部分是将interactivePopGestureRecognizer分配给self或相应的为零。

我正在考虑间歇性冻结主线程SDWebImage

假设您使用从downloadImageWithURL:options:progress:completed:完成的块下载的映像。如果是,请确保在使用映像之前将其分派到主队列。

如果直接使用SDWebImageDownloader,则完成块(如您所记下的)将在后台队列上调用,您可以在完成时使用主队列上的dispatch_async修复它。

否则,您可以使用: SDWebImageManager downloadImageWithURL:options:progress:completed 🙁调用主队列上的完成块的方法)。

如果问题仍然存在(只是因为你谈论“我的应用程序的一些独特的事情是,它是非常形象沉重..”)看也常见的问题,特别是处理图像刷新知道问题。

添加到您的支票也这个不错的代码片段:

 import UIKit.UINavigationController public typealias VoidBlock = (Void -> Void) public extension UINavigationController { public func pushViewController(viewController: UIViewController, animated: Bool, completion: VoidBlock) { CATransaction.begin() CATransaction.setCompletionBlock(completion) self.pushViewController(viewController, animated: animated) CATransaction.commit() } } 

也许可以帮助了解,如果pushViewController完成,如果完成所有viewControllers预期..

我试图做的另一个testing是启动与iOS 8.x和iPhone 6+的应用程序,因为在iOS 9的pureLayout项目中有一些问题 。你能发送有关这个testing的反馈吗?

在pushview操作之前,我还对真正的scrollview维度有一些怀疑,你可以通过检查视图层次来分析当前的视图吗?

尝试在主线程

 dispatch_async(dispatch_get_main_queue()){ UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController") // your code }