可以优化卸载在UIScrollView和PageControl中不再可见的视图+控制器

时间:2011-03-28 19:57:42

标签: iphone memory-management memory-leaks uiscrollview uipagecontrol

我有这个页面控制代码与apple示例相同。这里我有一个包含ImageView的子视图(controller.view)。现在问题在于内存管理。一切正常。但是当我滚动5-10页。 RAM被填满了。 我试图释放视图+控制器,但没有找到任何适当的地方/方式。我想发布当前不可见的视图。 (当前,上一个和下一个视图除外)

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    NSMutableArray *controllers = [[NSMutableArray alloc] init];
    for (unsigned i = 0; i < kNumberOfPages; i++) {
        [controllers addObject:[NSNull null]];
    }
    self.viewControllers = controllers;
    [controllers release];

    scrollView.pagingEnabled = YES;
    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    scrollView.scrollsToTop = NO;
    scrollView.delegate = self;

    pageControl.numberOfPages = kNumberOfPages;
    pageControl.currentPage = 0;

    [self loadScrollViewWithPage:0];
    [self loadScrollViewWithPage:1];
}
- (void)loadScrollViewWithPage:(int)page {
    if (page < 0) return;
    if (page >= kNumberOfPages) return;

    PageControlExampleViewControl *controller = [viewControllers objectAtIndex:page];
    if ((NSNull *)controller == [NSNull null]) {
        controller = [[PageControlExampleViewControl alloc] initWithPageNumber:page];
        [viewControllers replaceObjectAtIndex:page withObject:controller];
        [controller release];
    }

    if (nil == controller.view.superview) {
        CGRect frame = scrollView.frame;
        frame.origin.x = frame.size.width * page;
        frame.origin.y = 0;
        controller.view.frame = frame;
        [scrollView addSubview:controller.view];
    }
}

- (void)scrollViewDidScroll:(UIScrollView *)sender {
  if (pageControlUsed) {
        return;
    }
    CGFloat pageWidth = scrollView.frame.size.width;
    int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
    pageControl.currentPage = page;

    [self loadScrollViewWithPage:page - 1];
    [self loadScrollViewWithPage:page];
    [self loadScrollViewWithPage:page + 1];

}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender {
    int page = pageControl.currentPage;
    [self loadScrollViewWithPage:page - 1];
    [self loadScrollViewWithPage:page];
    [self loadScrollViewWithPage:page + 1];
    CGRect frame = scrollView.frame;
    frame.origin.x = frame.size.width * page;
    frame.origin.y = 0;
    [scrollView scrollRectToVisible:frame animated:YES];
    pageControlUsed = YES;
}

4 个答案:

答案 0 :(得分:4)

我尝试了几个小时的Deepmist代码。它完成了这项工作,但我收到了内存警告,我的应用程序每滚动25-30页就崩溃了(我在页面中使用大图像)。在Instruments中我注意到了很大的内存使用:即使从superview中删除了不必要的视图,并且相关的viewControllers被NSNulls取代,Instruments也显示每个页面滚动的实际内存增加了4-5MB!

在网上搜索我发现这是一个常见问题。如果您还遇到此问题,则应尝试以下检查:

1)在每个视图中,一定要使用imageWithContentsOfFile而不是imageNamed。作为记录的imageNamed缓存图像并增加内存大小。

2)在Deepmist代码中,之后:

[controller.view removeFromSuperview];

您还必须将视图设置为nil:

controller.view=nil;

这个技巧解决了内存消耗现在只有三个加载的视图(当前,当前-1和当前+ 1以避免在页面滚动中闪烁)的稳定性。

希望这有帮助!

答案 1 :(得分:1)

答案 2 :(得分:0)

在loadScrollViewWithPage方法中,就在if(nil == controller.view.superview)之前,循环通过所有视图并删除除当前-1,当前和当前+ 1之外的所有视图,但仅在使用当前索引视图调用方法时。另外,不要忘记使用NSNulls替换viewControllers数组中的那些视图控制器。

答案 3 :(得分:0)

尝试this VSScrollview,它重用其视图,如UITableview重用其单元格。