Getting UIPageViewController to clear its internal cache on didRecieveMemoryWarning is unintuitive

Originator:kmensah
Number:rdar://24526037 Date Originated:2/5/2016
Status: Resolved:
Product:iOS SDK Product Version:ios 8.1 - current
Classification:Performance Reproducible:Always
 
Bug ID 24526037

Description:

UIPageViewController does not give up any of the view controllers in its internal cache when didReceiveMemoryWarning is called. Furthermore, setViewControllers:direction:animated:completed adds to the retainCount in unexpected ways.

1) Calling setViewControllers:direction:animated:completed before you've added the UIPageViewController to the controller view hierarchy adds an extra ref to the first view controller that makes it never get deallocated. 

2) To get the UIPageViewController to clear it's internal cache, you can call setViewControllers:direction:animated:completed with the visible view controller and animated set to NO. But this will add refs to the visible view controller that never get cleared.

3) You can get around 2) by first calling setViewControllers:direction:animated:completed with a dummy view controller and then the visible view controller. As long as the dummy view controller is relatively inexpensive compared to actual pages this works out well.

I've attached an example project as a zip and it's also reachable at https://drive.google.com/file/d/0BzO-ucTGhRD0T3pVcklqdFhpUEU/view?usp=sharing


Steps to reproduce:

For problem 1)

In the example project attached comment out RootViewController's didReceiveMemoryWarning implementation.

In viewDidLoad move the definition of startViewController and the first call to setViewControllers:direction:animated:completed before the call to self.addChildVieController (where page view controller project template originally has it).

Comment out the initialization of _dummyViewController.

Run the app in Instruments using the Allocations tool/scheme.

Scroll through the pages all way to the right. You'll see DataViewController objects being alloced/dealloced but the first instance will always still be alive.

For Problem 2)

In the example project attached, in RootViewController's didReceiveMemoryWarning, uncomment [self clearPageViewControllerCacheWithExtraRef]; and comment [self clearPageViewControllerCache];

Comment out the initialization of _dummyViewController.

Run the app in Instruments using the Allocations tool/scheme.

Scroll to Febuary's page. There's be 3 DataViewControllers. Note the retain count of the current visible view controller.

Trigger a memory warning. Not how tthe retain count of the visible view controller has increased.

See the number of instances of DataViewController go down to one.

Scroll to the right to March's page. Trigger another Memory warning.

See that there's 2 DataViewControllers still alive. 

For Problem 3)

In the example project attached, in RootViewController's didReceiveMemoryWarning, comment [self clearPageViewControllerCacheWithExtraRef]; and uncomment [self clearPageViewControllerCache];

Run the app in Instruments using the Allocations tool/scheme.

Scroll to Febuary's page. There'll be four DataViewControllers. Note the retain count of the current visible view controller.

Trigger a memory warning. Not how the retain count of the visible view controller is the same.

See the number of instances of DataViewController go down to two.

Scroll to the right to March's page. Trigger another Memory warning.

See that there's only two DataViewControllers still alive. 

Expected Results:

[UIPageViewController didReceiveMemoryWarning] gives up ownership of view controllers that aren't on screen. Or there is an option that lets us do this ourselves if this is not an acceptable default.

Actual Results:

The steps to get this internal cache cleared are unclear and unintuitive. 

Configuration:

Seen in Simulator (iPad2) and hardware (iPad Mini, iPhone 6)

Version and Build:

iOS 9.2 (but seen in iOS 8.1 also)

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!