簡體   English   中英

UIPageViewController在內存不足時翻轉過快時崩潰

[英]UIPageViewController crashes when flipped too fast during low memory

由於Xcode的UIPageViewController模板緩存了所有頁面數據,我遇到了一些內存問題,因此我將其更改為動態加載頁面,所以現在當我的應用程序收到內存不足警告時,它會釋放內存以便頁面不顯示,但是如果用戶通過點擊屏幕邊緣快速翻閱頁面,它仍然會崩潰。 我猜這是因為當調用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];
}

我認為你的假設是正確的,因為我也經歷了類似的行為:當你翻到下一頁時,為了使事情很好地動畫,新頁面在舊的頁面被釋放之前被分配,並且需要一些時間舊的一個被解除分配。 因此,當你足夠快地翻轉時,對象的分配速度比它們被解除分配的速度快,並且最終(實際上很快),你的應用程序因內存使用而被殺死。 如果您遵循Instruments中內存的分配/釋放,則在翻頁時的釋放延遲變得非常明顯。

你有三種方法,IMO:

  1. 實現“光” viewDidLoad方法(實際上,整個初始化/初始顯示序列):在某些應用程序中,例如,加載低分辨率圖像而不是將要顯示的高分辨率圖像是有意義的; 或者,稍微延遲頁面所需的額外資源分配(數據庫訪問,聲音等);

  2. 使用一個頁面池,比如一個三頁(或5個,取決於你的應用程序)的數組,你繼續“重用”,以便你的應用程序的內存配置文件保持穩定並避免尖峰;

  3. 仔細檢查分配和釋放內存的方式; 從這個意義上說,你經常讀到自動釋放為釋放/釋放機制添加了一些“慣性”,這很容易理解:如果你有一個自動釋放的對象,只有當你循環通過它時,它才會被它的釋放池釋放。主循環(對於主發布池,這是正確的); 因此,如果您在翻頁時調用了很長的方法序列,這將使發布/ dealloc稍后發生。

在內存使用優化方面沒有神奇的內容,這是非常詳細和艱苦的工作,但是如果您查看代碼並應用這3條准則,IME將能夠減少應用程序的內存配置文件。 特別是,檢查儀器中的內存分配峰值並嘗試理解它們之間的關系是非常強大的。

這是我做的另一項更改,有人可能會發現有用的更改:

基本上,我只允許新頁面開始,如果前一個頁面已完成。

我使用Apple的默認PageViewController項目作為模板,因此我將使用該項目中定義的術語。

每當通過viewControllerAtIndex:請求頁面VC時,我在shouldDenyVC名為' 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委托方法pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:的末尾設置_modelController.shouldDenyPageTurn = NO pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

我還必須在任何預加載結束時設置_modelController.shouldDenyPageTurn = NO ,以便允許翻頁。

iOS5中存在一個錯誤,導致滾動視圖泄漏少量內存。

您是否嘗試在檢查分配和內存泄漏的儀器中分析應用程序?

您可以在模擬器中模擬低內存警告(硬件 - >模擬低內存警告)。 或者您可以通過代碼執行此操作(只需記住在調試后刪除,因為這會導致您的應用被拒絕!)

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

如果您使用strongretain屬性,那么在完成它們之后將它們設置為nil ,ARC將釋放它們指向幕后的內存。

如果要創建大量臨時對象(非屬性或未分配的對象),則插入自動釋放池:

@autoreleasepool {

}

最后,展示一些代碼,我們可以更好地幫助您。

由於您沒有發布任何代碼,因此很難猜出問題究竟在哪里。

  1. 要強制卸載視圖,您可以覆蓋viewDidDisappear:出現在UIPageViewController的那些viewcontroller類的方法。

    代碼看起來像:

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

    如果你還有didReceiveMemoryWarning覆蓋,請不要忘記調用[super didReceiveMemoryWarning]; 從中。

  2. 關於UIPageViewControllerDataSource方法如何工作也會有一些混亂 - 你可能會有一些'混合線'。 檢查接受的答案在這里

它可能是由渲染引起的。 當鰭狀肢過快時,重繪“頁面”所使用的內存和CPU將迅速增加。 如果您在UIPageViewController中使用的視圖基於CALayer並且頁面太多,則翻轉太快肯定會使App崩潰。

一種解決方案是自定義圖層並緩存渲染結果。 僅在必須時重新呈現內容。 但緩存可能會增加內存使用量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM