UIScrollView и реальная память - PullRequest
2 голосов
/ 31 января 2012

Я наблюдал за сеансом WWDC 2010 104 о реализации тайлинга в UIScrollView и пытался реализовать его с некоторыми изменениями, но у меня есть проблема с реальной памятью - я добавляю UIImageView в качестве подпредставления для UIScrollView и даже пытался удалить супер просмотр сразу после добавления - и я не очистил свою настоящую память. Может быть, есть проблема с автоматическим выпуском?

- (void)tilePages 
{
    [scrollView setContentSize:CGSizeMake(scrollView.bounds.size.width * [images count], scrollView.bounds.size.height)]; 

    CGRect visibleBounds = scrollView.bounds;
    int firstNeededPageIndex = floorf(CGRectGetMinX(visibleBounds) / CGRectGetWidth(visibleBounds));
    int lastNeededPageIndex  = floorf((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds));
    firstNeededPageIndex = MAX(firstNeededPageIndex, 0);
    lastNeededPageIndex  = MIN(lastNeededPageIndex, ([images count] - 1));

    for (ImageScrollView *page in visiblePages) {
        if (page.index < firstNeededPageIndex || page.index > lastNeededPageIndex) {
            [recycledPages addObject:page];
            [page removeFromSuperview];
        }
    }

    [visiblePages minusSet:recycledPages];

    for (int index = firstNeededPageIndex; index <= lastNeededPageIndex; index++) {
        if (![self isDisplayingPageForIndex:index]) {
            ImageScrollView *page = [self dequeueRecycledPage];
            if (page == nil) {
                page = [[[ImageScrollView alloc] init] autorelease];

                [page setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];

                if (self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
                    [page setContentMode:UIViewContentModeScaleAspectFill];
                } 
                else {
                    [page setContentMode:UIViewContentModeScaleAspectFit];
                }
            }
            [self configurePage:page forIndex:index];

            [scrollView addSubview:page];

            [visiblePages addObject:page];
        }
    }    
}

- (ImageScrollView *)dequeueRecycledPage
{
    ImageScrollView *page = [recycledPages anyObject];
    if (page) {
        [[page retain] autorelease];
        [recycledPages removeObject:page];
    }
    return page;
}

- (BOOL)isDisplayingPageForIndex:(NSUInteger)index
{
    BOOL foundPage = NO;
    for (ImageScrollView *page in visiblePages) {
        if (page.index == index) {
            foundPage = YES;
            break;
        }
    }
    return foundPage;
}

- (void)configurePage:(ImageScrollView *)page forIndex:(NSUInteger)index
{
    page.index = index;
    page.frame = [self frameForPageAtIndex:index];
    [page displayImage:[self imageAtIndex:index]];
}

- (CGRect)frameForPagingScrollView 
{
    CGRect frame = scrollView.bounds;
    return frame;
}

- (CGRect)frameForPageAtIndex:(NSUInteger)index {
    CGRect pagingScrollViewFrame = [self frameForPagingScrollView];

    CGRect pageFrame = pagingScrollViewFrame;
    pageFrame.origin.x = (pagingScrollViewFrame.size.width * index);
    return pageFrame;
}

- (UIImage *)imageAtIndex:(NSUInteger)index {
    return [images objectAtIndex:index];   
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.scrollView = nil;
    self.textView = nil;
}

- (void)dealloc
{
     [super dealloc];
     [scrollView release];
     [images release];
     [recycledPages release];
     [visiblePages release];
}

1 Ответ

0 голосов
/ 31 января 2012

Вы правильно внедрили демо, не считая одной части. Предполагается, что память освобождается на линии

[visiblePages minusSet:recycledPages];

Но я вижу, что вы храните ваши изображения в массиве. Ваши изображения хранятся в этом массиве и не освобождаются, поэтому они занимают память.

Цель этого кода - лениво загружать изображения по мере необходимости. Вы публикуете не там, где инициализируете массив изображений, а из того, что у вас есть, он выглядит предварительно заполненным изображениями.

Вместо этого вам следует сохранить пути к изображениям в массиве (все, что вы сделали с ним до сих пор, будет работать), а затем изменить следующий метод:

- (UIImage *)imageAtIndex:(NSUInteger)index {
    NSSting * imagePath = [images objectAtIndex:index];
    UIImage * image = [UIImage imageWithContentsOfFile:imagePath];
    return image;   
}

Или что-то на этот счет. Могут быть более эффективные способы загрузки изображения в зависимости от того, откуда оно поступает, но приведенное выше должно остановить сбой.

Если ваши изображения загружаются очень долго и блокируют ваш интерфейс, вы можете сделать несколько вещей. Вы можете разгрузить загрузку изображения в фоновый поток, используя GCD, или вы можете продолжать смотреть это видео WWDC и реализовать CATiledLayer для изображения высокого разрешения и поместить его поверх изображения низкого разрешения. Изображение будет выглядеть очень быстрым.

...