我正在为基于.h
的图书的基于.m
的每个页面使用单独的.xib
,UIViewController
和UIPageViewController
个文件。每个页面都加载了动画,音乐等,并占用大约4MB的内存。在Instruments中,每个页面加载时,可用内存下降约4MB。翻页时,永远不会释放此内存。它最终会给出内存警告。 UIPageViewController
似乎保持每个页面在内存中实例化,并且不会卸载它。因此,当页面快速转动时,应用程序崩溃。
我希望能够卸载除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
后设置为nil。它没用。页面提升后页面仍然记忆良好。
//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;
}
我使用与向UIPageViewController
提供页面相同的方式查看了stackoverflow的帖子,但是没有找到任何接近的内容。最接近的是“ ARC在导航控制器中”返回“时不释放内存”,但不会以相同的方式设置视图控制器。
我试图将不需要的页面设置为nil,因此ARC可以毫无运气地删除它们。我应该尝试任何建议或替代路径?我喜欢页面卷曲效果,并且无法在其他地方找到一个好的水平页面卷发。
谢谢!埃里克
答案 0 :(得分:13)
“UIPageViewController似乎保持每个页面在内存中实例化”
不,你是通过实例化所有这些“页面”(控制器)并将它们放入一个数组(当你翻页时内存跳转,因为控制器的视图实际上没有加载,直到你显示它,甚至虽然控制器已经实例化了。但是一旦你完成了,你的控制器就会保留它的视图并且数组会保留控制器。你只需要保留一些你所在页面的数量,并在viewControllerBeforeViewController:和viewControllerAfterViewController:的实现中,在那里实例化一个页面。当您离开该页面时,其控制器将被取消分配。如果加载速度很慢,您可能需要保留一个包含当前页面的数组以及之前和之后的数组 - 如果您将其设置为滚动而不是页面卷曲以进行转换,则UIPageViewController会执行此操作。
我做了一个简单的测试应用程序:
@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方法中,当我离开它们时会调用它们。
答案 1 :(得分:1)
我知道这个问题有点老了,但也许我的方法可以帮助一些人在不使用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];
}
}
}
重要的是,只有在操作完成时才释放它们,因为否则下一页更改会尝试访问已发布的页面。
希望这有帮助!
答案 2 :(得分: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,内存不会一次又一次地滚动增加。 希望这会对你有所帮助。