在UIScrollView iOS7中延迟加载图像时,内存会增加

时间:2014-01-31 07:01:58

标签: ios memory scrollview lazy-loading

每次滚动到新图像时,我的应用程序的“实时字节数”会继续增加约600kb。我懒洋洋地加载我的图像,一次只有3个,加载到水平页面的UIScrollView。我已经运行了Xcode仪器,我相信我已经将问题跟踪到了这一行:

newPageView = [[UIImageView alloc] initWithImage:[self.album objectAtIndex:page]];

每个加载的页面都会创建一个新的UIImageView实例,由于某种原因,该空间将保存在内存中。我正在使用ARC和XCode5。由于ARC中没有办法'dealloc'对象,释放这些内存的最佳方法是什么?

这是我的乐器的快照,显示了不断占用记忆的图像: enter image description here

我已经在网上看到了其他领域提出的这个问题,但找不到有帮助的答案。我对编码很新,但非常愿意学习,任何参考文献都将非常感谢!谢谢!

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    self.pageCount = self.album.count;

    // Set up the array to hold the views for each page
    self.pageViews = [[NSMutableArray alloc] init];
    for (NSInteger i = 0; i < self.pageCount; ++i) {
        [self.pageViews addObject:[NSNull null]];
    }

    NSInteger p = self.page;
    CGFloat w = self.scrollView.bounds.size.width;
    [self.scrollView setContentOffset:CGPointMake(p*w,0) animated:YES];

    // Set up the content size of the scroll view
    CGSize pagesScrollViewSize = self.scrollView.frame.size;
    self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * self.pageCount, pagesScrollViewSize.height);

    // Load the initial set of pages that are on screen
    [self loadVisiblePages];
}

- (void)loadVisiblePages {

    // First, determine which page is currently visible
    CGFloat pageWidth = self.scrollView.frame.size.width;

    NSInteger page = (NSInteger)floor((self.scrollView.contentOffset.x * 2.0f + pageWidth) / (pageWidth * 2.0f));

    // Keeps track of which image is showing, for passing to child view controller
    self.currentImage = [self.album objectAtIndex:page];
    self.title =[NSString stringWithFormat:@"%d of %d", [self.album indexOfObject:self.currentImage]+1, self.pageCount];

    // Work out which pages we want to load
    NSInteger firstPage = page - 1;
    NSInteger lastPage = page + 1;

    // Purge anything before the first page
    for (NSInteger i=0; i<firstPage; i++) {
        [self purgePage:i];
    }
    for (NSInteger i=firstPage; i<=lastPage; i++) {
        [self loadPage:i];
    }
    for (NSInteger i=lastPage+1; i<self.pageCount; i++) {
        [self purgePage:i];
    }
}

- (void)loadPage:(NSInteger)page {

    if (page < 0 || page >= self.pageCount) {
        // If it's outside the range of what we have to display, then do nothing
        return;
    }

    // Load an individual page, first seeing if we've already loaded it
    UIView *pageView = [self.pageViews objectAtIndex:page];
    // create an instance of imageView to be used as the newPageView
    UIImageView *newPageView;

    if ((NSNull*)pageView == [NSNull null]) {
        CGRect frame = self.scrollView.bounds;
        frame.origin.x = frame.size.width * page;
        frame.origin.y = 0.0f;

        newPageView = [[UIImageView alloc] initWithImage:[self.album objectAtIndex:page]];

        newPageView.contentMode = UIViewContentModeScaleAspectFit;
        newPageView.frame = frame;
        [self.scrollView addSubview:newPageView];

        [self.pageViews replaceObjectAtIndex:page withObject:newPageView];
    }
}

- (void)purgePage:(NSInteger)page {
    if (page < 0 || page >= self.pageCount) {
        // If it's outside the range of what we have to display, then do nothing
        return;
    }

    // Remove a page from the scroll view and reset the container array
    UIView *pageView = [self.pageViews objectAtIndex:page];
    if ((NSNull*)pageView != [NSNull null]) {
        [pageView removeFromSuperview];
        [self.pageViews replaceObjectAtIndex:page withObject:[NSNull null]];
        [self.album replaceObjectAtIndex:page withObject:[NSNull null]];
    }

}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {

    [self loadVisiblePages];
}

3 个答案:

答案 0 :(得分:1)

ARC尝试自动释放内存,因此您不必担心这样做。

但是,您可以“标记”对象,以便通过“弄脏”它们来释放它们:

yourobject = nil;

这种告诉IOS设备该对象未被使用并且可以被释放。如果您正在将图像加载到滚动视图中,这意味着当用户向下滚动时,内存中仍有内容不在屏幕上,因此不需要。您可以摆脱这些图像,然后在滚动视图接近某一点时再次加载它们 您可以在此问题中找到答案(与您的问题非常相似):Memory pressure in app

答案 1 :(得分:0)

如果没有看到您的代码,很难给出答案,但我想当您谈到“延迟加载”时,您的意思是您只在需要时将图像添加到滚动视图中。但是,如果没有显示滚动视图中的图像,是否将其删除?

我不知道您想要哪种显示方式,但请查看UICollectionView。集合视图管理内存本身,仅在需要时显示单元格,UICollectionViewLayout允许您自定义集合视图。

答案 2 :(得分:0)

我已经更改了我的代码,以便在按照以下方式加载图片时调整图片大小:

   - (void)loadPage:(NSInteger)page {

    if (page < 0 || page >= self.pageCount) {
        // If it's outside the range of what we have to display, then do nothing
        return;
    }

    // Load an individual page, first seeing if we've already loaded it
    UIView *pageView = [self.pageViews objectAtIndex:page];
    // create an instance of imageView to be used as the newPageView
    UIImageView *newPageView;

    if ((NSNull*)pageView == [NSNull null]) {
        CGRect frame = self.scrollView.bounds;
        frame.origin.x = frame.size.width * page;
        frame.origin.y = 0.0f;

        self.resizeImage = [self.album objectAtIndex:page];
        UIImage *theImage = [self resizeImage:self.resizeImage toWidth:320.0f andHeight:480.0f];

        newPageView = [[UIImageView alloc] initWithImage:theImage];

        newPageView.contentMode = UIViewContentModeScaleAspectFit;
        newPageView.frame = frame;
        [self.scrollView addSubview:newPageView];

        [self.pageViews replaceObjectAtIndex:page withObject:newPageView];
    }
}

- (UIImage *)resizeImage:(UIImage *)image toWidth:(float)width andHeight:(float)height  {
    CGSize newSize = CGSizeMake(width, height);
    CGRect newRectangle = CGRectMake(0, 0, width, height);
    UIGraphicsBeginImageContext(newSize);
    [self.resizeImage drawInRect:newRectangle];
    UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return resizedImage;
}

这似乎将内存保持在稳定的位置,而内存消耗没有永久性增加。我不确定这是否是解决此问题的最佳方法,所以如果有人有任何更好的想法,请提供帮助。