Releasing unused pages in UIPageViewController

巧了我就是萌 提交于 2019-12-03 00:23:01

"UIPageViewController seems to keep each page it instantiates in memory"

No, you're doing that by instantiating all those "pages" (controllers), and putting them into an array (the memory jumps as you turn the page because the controller's view is not actually loaded until you display it, even though the controller has been instantiated. But once you've done that, your controller retains its view and the array retains the controller). You just need to keep some kind of count of which page you're on, and in the implementation of viewControllerBeforeViewController: and viewControllerAfterViewController:, instantiate a page there. When you go away from that page, its controller will be dealloc'd. If the loading is slow, you might need to keep an array that has the current page and the ones before and after -- UIPageViewController does do that if you have it set to scroll instead of page curl for the transition.

I made a simple test app like this:

@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;
}

My example only has 3 pages, but it illustrates one way to do this. I put logs in the dealloc methods of the 3 controllers, and they were called when I navigated away from them.

I know this question is a bit older, but maybe my approach can help some people facing the same issue when not using ARC.

I think the best way to release unused pages is in the didFinishAnimation method of the UIPageViewController. You get the 1 or 2 previous view controllers there and you can easily release them. I do it like this:

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

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

It is important that you only release them if the action was completed because otherwise with the next page change you would try to access released pages.

Hope this helps!

I encounter this problem this time. And after an hour thinking,I had find a solution.

This is my .h file

#import <UIKit/UIKit.h>

@interface BKContentViewController : UIPageViewController

@end

And my .m file and viewDidload method

- (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];
}

And the most important.

#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;
}

After this, I have only three viewContrller and the memory will not increase by scroll again and again. Hope this will help you.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!