【问题标题】:Possible optimization to unload the views+controllers which are no longer visible in UIScrollView and PageControl卸载在 UIScrollView 和 PageControl 中不再可见的视图+控制器的可能优化
【发布时间】:2011-07-24 18:37:44
【问题描述】:

我有这个与苹果示例相同的页面控制代码。这里我有一个包含 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;
}

【问题讨论】:

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


    【解决方案1】:

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

    在网上搜索我发现这是一个常见问题。如果你也有这个问题,你应该尝试以下检查:

    1) 在每个视图中,请务必使用 imageWithContentsOfFile 而不是 imageNamed。如记录的 imageNamed 缓存图像并增加内存大小。

    2) 在 Deepmist 代码中,之后:

    [controller.view removeFromSuperview];
    

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

    controller.view=nil;
    

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

    希望这会有所帮助!

    【讨论】:

    • 在敲了敲头之后为我工作。谢谢!
    • 把我的名字从 Deepmist 改成了 Joe。很高兴你能解决这个问题。
    【解决方案2】:

    我没有对此进行测试,但我想您可以编写一个与加载相反的方法:

    - (void)unloadScrollViewWithPage:(int)page {
        if (page < 0) return;
        if (page >= kNumberOfPages) return;
    
        PageControlExampleViewControl *controller = [viewControllers objectAtIndex:page];
    
        if ((NSNull *)controller != [NSNull null]) {
            if (nil != controller.view.superview)
                [controller.view removeFromSuperview];
    
            [viewControllers replaceObjectAtIndex:page withObject:[NSNull null]];            
        }
    }
    

    然后像这样在你的 didScroll 方法中添加一些代码:

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

    【讨论】:

    • 我试过你的帮助 :) 在这里我面临同样的问题。我们正在从超级视图中删除视图,同时替换它将为空。所以我收到 EXC_BAD_ACCESS 错误。 “正在完成的修改层”。有什么方法可以等到操作完成或延迟?
    • 我不确定您为什么会收到该错误。也许代码的另一部分是在视图发布后尝试使用它?我使用相同的滚动视图代码将此代码添加到我自己的项目中,它似乎删除了视图而没有任何错误。
    【解决方案3】:

    在 loadScrollViewWithPage 方法中,就在 if (nil == controller.view.superview) 之前,循环遍历所有视图并将它们全部删除,除了当前 -1、当前和当前 + 1,但前提是使用当前索引视图调用方法。另外,不要忘记用 NSNulls 替换 viewControllers 数组中的那些视图控制器。

    【讨论】:

      【解决方案4】:

      试试this VSScrollview ,它重用它的视图就像 UITableview 重用它的单元格一样。

      【讨论】:

        猜你喜欢
        • 2017-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-06
        • 2011-03-16
        • 1970-01-01
        相关资源
        最近更新 更多