UIPageViewController memory leak

2020-02-08 09:12发布

It seems that UIPageViewController is holding the initial content view controller forever. For example:

DataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = @[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self.modelController;

The startingViewController is never released until the pageViewController itself it released.

To reproduce this bug, just create a new project in XCode using the Page-Based Application template. And add 3 lines of code into DataViewController.m

@property NSInteger debugIndex; // file scope
NSLog(@"DataViewController[%d] created", self.debugIndex); // in viewDidLoad
NSLog(@"DataViewController[%d] dealloc", self.debugIndex); // in dealloc

And when you scroll the demo App in vertical orientation, you'll get logs like this:

DataViewController[0] created  
DataViewController[1] created  
DataViewController[2] created  
DataViewController[1] dealloc  
DataViewController[3] created  
DataViewController[2] dealloc  
DataViewController[4] created  
DataViewController[3] dealloc  
DataViewController[5] created  
DataViewController[4] dealloc  
DataViewController[6] created  
DataViewController[5] dealloc  

DataViewController[0] is never deallocated.

Any ideas about this? Thanks!

5条回答
欢心
2楼-- · 2020-02-08 09:29

same problem here i resolved it by keeping my initial viewController in the variable and instead of creating the same vc on particular pageIndex i just reuse it

查看更多
一纸荒年 Trace。
3楼-- · 2020-02-08 09:39

I had same problem and solved the following:

[startingViewController release]; where the end point of initialization.

then the first ViewController will be deallocated.

查看更多
The star\"
4楼-- · 2020-02-08 09:40

Are you using transitionStyle UIPageViewControllerTransitionStyleScroll? I encountered the same or a similar problem which seemed to disappear when using page curl animations instead.

The problem was compounded for me because I was allowing a UISliderBar to set the position in the content. So on change of the UISliderBar, I was calling setViewControllers:direction:animated:completion: which caused more and more view controller references to get "stuck" in my UIPageViewController.

I am also using ARC. I have not found an acceptable way to force the UIPageViewController to let go of the extra view controller references. I will probably either end up using the page curl transition or implementing my own UIPageViewController equivalent using a UIScrollView with paging enabled so I can manage my own view controller cache instead of relying on UIPageViewController's broken view controller management.

查看更多
混吃等死
5楼-- · 2020-02-08 09:40

I'm not sure you still got the problem, but I had the same problem and I found the solution.

I don't know the reason, but it works.

I'm setting the first viewController right after addSubview, rather than before addChlidViewController.

-(void)settingPageViewController{
if (!self.pageViewController) {
    self.pageViewController = [[UIPageViewController alloc]initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
    self.pageViewController.delegate = self;
    self.pageViewController.dataSource = self;
    [self addChildViewController:self.pageViewController];
    [self.pageViewController didMoveToParentViewController:self];
    [self.containerView addSubview:self.pageViewController.view];
    [self.pageViewController setViewControllers:@[[self viewcontrollerAtIndex:0]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}    
}

and the first viewController will dealloc in the right time.

also, I found if call

        [self.pageViewController setViewControllers:@[[self viewcontrollerAtIndex:0]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:^(BOOL finished){
        NSLog(@"finished : %d",finished);
    }];

before addSubView and the completion block will not call.

and I reckon this block is the reason why the first viewController didn't dealloc.

I'll go find out why it didn't callback, and improve the answer~

cheers

查看更多
我欲成王,谁敢阻挡
6楼-- · 2020-02-08 09:50

After a few attempts to figure out what was happening on a similar issue, I noticed that in my project there were 2 reasons that caused a retain problem and resulted in having a UIPageViewController being forever retained.

1) there was a circular reference between the UIPageViewController and the UIViewcontroller that was presented (this was fixed by changing the properties to weak from strong in both classes)

2) and the main fix consisted in changing

[self setViewControllers:@[initialDetailsViewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];

to

__weak __typeof__(self) weakSelf = self;
    [weakSelf setViewControllers:@[initialDetailsViewController] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];

I hope this helps someone

查看更多
登录 后发表回答