9

我为基于图画书的每个基于页面使用单独.h.m, 和文件。每个页面都加载了动画、音乐等,大约需要 4MB 的内存。在 Instruments 中,随着每一页的加载,可用内存会下降约 4MB。当页面被翻页时,这个内存永远不会被释放。它最终会给出内存警告。 似乎将它实例化的每个页面都保留在内存中并且不会卸载它。因此,当页面快速翻动时,应用程序就会崩溃。.xibUIViewControllerUIPageViewControllerUIPageViewController

我希望能够卸载除UIPageViewController前一页、当前页和下一页所需的 3 个以外的所有页面。我如何卸载不需要的页面,因为它们是由UIPageViewController.

下面是UIPageViewController从中提取的页面数组。所有页面(Page1、Page2 等)基本上只是加载图像文件、提供基本动画和音乐。

    //ARRAY OF PAGES    
pageArray = [[NSArray alloc] initWithObjects:
        (id)[[Page1 alloc] initWithNibName:nil bundle:nil],
            [[Page2 alloc] initWithNibName:nil bundle:nil],    
            [[Page3 alloc] initWithNibName:nil bundle:nil],    
            [[Page4 alloc] initWithNibName:nil bundle:nil],    
            [[Page5 alloc] initWithNibName:nil bundle:nil],    
            [[Page6 alloc] initWithNibName:nil bundle:nil], 
            [[Page7 alloc] initWithNibName:nil bundle:nil],
            [[Page8 alloc] initWithNibName:nil bundle:nil],
             // continues all the way up to page 47
             [[Page47 alloc] initWithNibName:nil bundle:nil],
             nil];

我省略了UIPageViewController. 它使用“ nextPageNumber”从pageArray上面拉出正确的页面来创建一个新的页面对象。

-(void)turnPageForward{

[pageController setViewControllers:[NSArray arrayWithObject:[pageArray objectAtIndex:nextPageNumber]]
                         direction:UIPageViewControllerNavigationDirectionForward
                          animated:YES completion:^(BOOL finished){
                          }];

}

我尝试创建一个对象“ pageIndex”(见下文),在将其提供给pageController. 它没有用。页面前进后,该页面仍会占用大量内存。

//PROGRAM PAGE FORWARD

-(void)turnPageForward{

UIViewController * pageIndex =[pageArray objectAtIndex:nextPageNumber];  //nextPageNumber is the next page to load

[pageController setViewControllers:[NSArray arrayWithObject:pageIndex]
                         direction:UIPageViewControllerNavigationDirectionForward 
                          animated:YES completion:^(BOOL finished){
                          }];                                  
pageIndex = nil;                            

}

我已经使用相同的向 提供页面的方式查看了 stackoverflow 的帖子UIPageViewController,但没有找到任何接近的东西。最接近的是“在导航控制器中“返回”时 ARC 不释放内存”,但没有以相同的方式设置视图控制器。

我试图将不需要的页面设置为 nil,以便 ARC 可以在没有运气的情况下删除它们。我应该尝试任何建议或替代路径吗?我喜欢卷页效果,但在其他地方找不到一个很好的水平卷页效果。

谢谢!埃里克

4

3 回答 3

14

“UIPageViewController 似乎将它实例化的每个页面都保存在内存中”

不,您是通过实例化所有这些“页面”(控制器)并将它们放入数组中来做到这一点的(当您翻页时内存会跳转,因为控制器的视图在您显示它之前实际上并未加载,即使控制器已经实例化了。但是一旦你这样做了,你的控制器会保留它的视图,而数组会保留控制器)。你只需要对你所在的页面进行某种计数,并在 viewControllerBeforeViewController: 和 viewControllerAfterViewController: 的实现中,在那里实例化一个页面。当您离开该页面时,其控制器将被释放。如果加载缓慢,

我做了一个这样的简单测试应用程序:

@implementation ViewController {
    int count;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    count = 1;
    self.pager = [[UIPageViewController alloc]initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationDirectionForward options:nil];
    self.pager.dataSource = self;
    self.pager.delegate = self;
    Page1 *first = [[Page1 alloc] initWithNibName:@"Page1" bundle:nil];
    [self.pager setViewControllers:@[first] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
    [self addChildViewController:self.pager];
    [self.view addSubview:self.pager.view];
    [self.pager didMoveToParentViewController:self];
}


-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController {
    if (count > 1) {
        NSString *nibName = [@"Page" stringByAppendingFormat:@"%d",count-1];
        UIViewController *prev = [[NSClassFromString(nibName) alloc] initWithNibName:nibName bundle:nil];
        count -= 1;
        return prev;
    }
    return nil;
}

-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController {
    if (count < 3) {
        NSString *nibName = [@"Page" stringByAppendingFormat:@"%d",count+1];
        UIViewController *next = [[NSClassFromString(nibName) alloc] initWithNibName:nibName bundle:nil];
        count += 1;
        return next;
    }
    return nil;
}

我的示例只有 3 页,但它说明了执行此操作的一种方法。我将日志放在 3 个控制器的 dealloc 方法中,当我离开它们时调用它们。

于 2013-02-07T16:50:03.953 回答
2

我知道这个问题有点老了,但也许我的方法可以帮助一些在不使用 ARC 时面临同样问题的人。

我认为释放未使用页面的最佳方法是在 UIPageViewController 的 didFinishAnimation 方法中。您在那里获得了 1 或 2 个以前的视图控制器,并且您可以轻松地释放它们。我这样做:

-(void)pageViewController:(UIPageViewController *)thePageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {

    if(completed) {
        for (UIViewController *viewController in previousViewControllers) {
             [viewController release];
        }
     }
}

重要的是,只有在操作完成时才释放它们,否则在下一次页面更改时,您将尝试访问已发布的页面。

希望这可以帮助!

于 2013-10-16T12:11:52.507 回答
0

这次我遇到了这个问题。经过一个小时的思考,我找到了解决方案。

这是我的 .h 文件

#import <UIKit/UIKit.h>

@interface BKContentViewController : UIPageViewController

@end

还有我的 .m 文件和 viewDidload 方法

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    self.delegate = self;
    self.dataSource = self;

    [self setViewControllers:[NSArray arrayWithObject:detailContent]
                   direction:UIPageViewControllerNavigationDirectionForward
                    animated:NO
                  completion:NULL];
}

而最重要的。

#pragma mark - UIPageViewControllerDataSource UIPageViewControllerDelegate

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{
    if (completed) {
        [self setViewControllers:[NSArray arrayWithObject:detailContent]
                       direction:UIPageViewControllerNavigationDirectionForward
                        animated:NO
                      completion:NULL];
    }

}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController{


    if (!detailRight) {
        detailRight = [[DetailContent alloc] init];
        [detailRight setShouldReturn:YES];
        [detailRight setPath:fPath withFileName:fName];
    }
    return detailRight;
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController{

    if (!detailLeft) {
        detailLeft = [[DetailContent alloc] init];
        [detailLeft setShouldReturn:YES];
        [detailLeft setPath:fPath withFileName:fName];
    }

    return detailLeft;
}

- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation{
    UIViewController *currentViewController = [self.viewControllers objectAtIndex:0];
    NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];
    [self setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];

    self.doubleSided = NO;
    return UIPageViewControllerSpineLocationMin;
}

在此之后,我只有三个 viewContrller 并且一次又一次滚动不会增加内存。希望这会帮助你。

于 2014-07-01T09:04:29.710 回答