UIPageViewController在内存不足时翻转速度过快时会崩溃

我有一些内存问题,由于Xcode的UIPageViewController的模板caching所有的页面数据,所以我改变它来dynamic加载页面,所以现在当我的应用程序收到一个低内存警告,它释放页面的内存不显示,但如果用户正在通过点击屏幕边缘来真正快速地浏览页面,它仍然崩溃。 我猜这是因为当didReceiveMemoryWarning被调用时,它不能足够快地释放内存。 如果用户慢慢翻转,它可以正常工作。 我限制了用户翻转页面的速度,但仍然发生。 我希望能够在每次翻页时释放内存,而不必等待低内存警告。 我正在使用ARC。 有没有办法做到这一点? 还有什么我可以做,以防止这一点? 谢谢。

编辑:

(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController { NSUInteger index = [self indexOfViewController:(SinglePageViewControllerSuperclass *)viewController]; if ((index == 0) || (index == NSNotFound)) { return nil; } index--; return [self viewControllerAtIndex:index]; } (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController { NSUInteger index = [self indexOfViewController:(SinglePageViewControllerSuperclass *)viewController]; if (index == NSNotFound || index == MAX_PAGE_INDEX) { return nil; } return [self viewControllerAtIndex:++index]; } 

我认为你的假设是正确的,因为我也经历了一个类似的行为:当你翻到下一页时,也是为了很好地animation的事情,新的页面被分配之前,旧的被释放,需要一些时间旧的一个被释放。 所以,当你翻转得足够快时,对象被分配的速度比被释放的速度快,最终(实际上很快),你的应用程序因内存使用而被终止。 如果您按照Instruments的内存分配/释放操作,页面翻页时的解除分配延迟非常明显。

IMO有三种方法:

  1. 实现一个“light” viewDidLoad方法(实际上是整个初始化/初始显示序列):在某些应用中,例如加载一个低分辨率的图像而不是显示的高分辨率图像是有意义的。 或者,稍微延迟您的页面需要的额外资源的分配(db访问,声音等);

  2. 使用一组页面(例如一个由三个页面组成的数组(或5个,这取决于您的应用程序),您保持“重用”,以便应用程序的内存configuration文件保持稳定并避免尖峰;

  3. 仔细审查你分配和释放内存的方式; 从这个意义上讲,你经常阅读autorelease在release / deallocation机制中添加一些“惰性”,这很容易理解:如果你有一个autoreleased对象,只有当你循环主循环(对于主版本池来说是这样的); 所以,如果你在页面翻页的时候调用了很长的一系列的方法,这会让release / dealloc在稍后发生。

在内存使用优化方面没有什么神奇的东西,这是一个相当详细和艰苦的工作,但是如果您查看代码并应用这3条准则,则您将能够减less应用程序的内存configuration文件。 特别是,检查乐器内存分配的高峰,并试图了解它们所涉及的是非常强大的。

这是我做了一个额外的改变,有人可能会发现有帮助:

基本上,如果前一个结束,我只允许开始一个新的页面。

我使用苹果默认的PageViewController项目作为模板,所以我将使用该项目中定义的术语。

每当通过viewControllerAtIndex:请求页面VC时,我在ModelController上设置一个名为“ shouldDenyVC ”的布尔值为YES

在我的EbookViewController这是UIPageViewController的委托,我捕获手势识别器,并分配EbookViewController作为他们的代表:

 self.view.gestureRecognizers = self.pageViewController.gestureRecognizers; for (UIGestureRecognizer *gr in self.view.gestureRecognizers) { gr.delegate = self; } 

然后,我可以通过否认手势识别器来拒绝翻页。

 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch: (UITouch *)touch { if (_modelController.shouldDenyPageTurn == YES) { return FALSE; } return TRUE; } 

最后,我在UIPageViewController委托方法的结尾设置了_modelController.shouldDenyPageTurn = NO pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

我还必须在任何预加载结束时将_modelController.shouldDenyPageTurn = NO设置为允许翻页。

在iOS5中有一个错误,导致滚动视图泄漏less量的内存。

你有没有尝试分析你的应用程序在仪器检查分配和内存泄漏?

您可以模拟模拟器中的低内存警告(硬件 – >模拟低内存警告)。 或者你可以通过代码来实现,(只要记得在debugging之后删除,因为这会让你的应用程序被拒绝!)

 [[UIApplication sharedApplication] performSelector:@selector(_performMemoryWarning)]; 

如果你使用strongretain属性,那么在完成它们之后将它们设置nil ,ARC将释放它们在幕后指向的内存。

如果你正在创build大量的临时对象(非属性对象或未分配的对象),则插入一个自动释放池:

 @autoreleasepool { } 

最后,显示一些代码,我们可以更好地帮助你。

这可能是由渲染造成的。 当翻转速度太快,重绘“页面”所使用的内存和CPU将迅速增加。 如果您在UIPageViewController中使用的视图基于CALayer,并且页面太多,翻转得太快肯定会使应用程序崩溃。

一种解决scheme是自定义图层并caching渲染结果。 仅在必须时重新呈现内容。 但是caching可能会增加内存使用量。

既然你没有发布任何代码,很难猜测你的问题到底在哪里。

  1. 要强制卸载视图,可以重写UIPageViewController中出现的UIPageViewController类的viewDidDisappear:方法。

    代码看起来像:

     - (void)viewDidDisappear:(BOOL)animated { [self didReceiveMemoryWarning]; } 

    如果你也有didReceiveMemoryWarning重写,不要忘记调用[super didReceiveMemoryWarning]; 从中。

  2. UIPageViewControllerDataSource方法的工作方式上也可能有一些混淆 – 你可能有一些“混合线”。 检查接受答案在这里 。