2010-11-30 2 views
1

Существует проблема в ScrollViewSuite. он использует больше памяти, чем необходимо. например:Пример кода ScrollViewSuite Использует больше памяти, чем необходимо?

  1. Загрузка изображения в 25% и измерения памяти (4 MB)
  2. Увеличить в изображении до 100% и измерить память (30 МБ)
  3. Уменьшить до 25% и измерения памяти (30 МБ) - почему 30? он должен использовать только 4 МБ - вот в чем проблема.

Как исправить проблему?

/***********************************************************************************/ 
/* Most of the work of tiling is done in layoutSubviews, which we override here. */ 
/* We recycle the tiles that are no longer in the visible bounds of the scrollView */ 
/* and we add any tiles that should now be present but are missing.    */ 
/***********************************************************************************/ 

- (void)layoutSubviews 
{ 
[self updateResolution]; 
NSLog(@"layoutSubviews "); 
    [super layoutSubviews]; 

    CGRect visibleBounds = [self bounds]; 

    // first recycle all tiles that are no longer visible 
    for (UIView *tile in [tileContainerView subviews]) { 

     // We want to see if the tiles intersect our (i.e. the scrollView's) bounds, so we need to convert their 
     // frames to our own coordinate system 
     CGRect scaledTileFrame = [tileContainerView convertRect:[tile frame] toView:self]; 

     // If the tile doesn't intersect, it's not visible, so we can recycle it 
     if (! CGRectIntersectsRect(scaledTileFrame, visibleBounds)) { 
      [reusableTiles addObject:tile]; 
      [tile removeFromSuperview]; 

     } 
    } 

    // calculate which rows and columns are visible by doing a bunch of math. 
    float scaledTileWidth = [self tileSize].width * [self zoomScale]; 
    float scaledTileHeight = [self tileSize].height * [self zoomScale]; 
    int maxRow = floorf([tileContainerView frame].size.height/scaledTileHeight); // this is the maximum possible row 
    int maxCol = floorf([tileContainerView frame].size.width/scaledTileWidth); // and the maximum possible column 
    int firstNeededRow = MAX(0, floorf(visibleBounds.origin.y/scaledTileHeight)); 
    int firstNeededCol = MAX(0, floorf(visibleBounds.origin.x/scaledTileWidth)); 
    int lastNeededRow = MIN(maxRow, floorf(CGRectGetMaxY(visibleBounds)/scaledTileHeight)); 
    int lastNeededCol = MIN(maxCol, floorf(CGRectGetMaxX(visibleBounds)/scaledTileWidth)); 

    // iterate through needed rows and columns, adding any tiles that are missing 
    for (int row = firstNeededRow; row <= lastNeededRow; row++) { 
     for (int col = firstNeededCol; col <= lastNeededCol; col++) { 

      BOOL tileIsMissing = (firstVisibleRow > row || firstVisibleColumn > col || 
            lastVisibleRow < row || lastVisibleColumn < col); 

      if (tileIsMissing) { 
       UIView *tile = [dataSource tiledScrollView:self tileForRow:row column:col resolution:resolution]; 

       // set the tile's frame so we insert it at the correct position 
       CGRect frame = CGRectMake([self tileSize].width * col, [self tileSize].height * row, [self tileSize].width, [self tileSize].height); 
       [tile setFrame:frame]; 
       [tileContainerView addSubview:tile]; 

       // annotateTile draws green lines and tile numbers on the tiles for illustration purposes. 
       [self annotateTile:tile]; 

      } 
     } 
    } 

    // update our record of which rows/cols are visible 
    firstVisibleRow = firstNeededRow; firstVisibleColumn = firstNeededCol; 
    lastVisibleRow = lastNeededRow; lastVisibleColumn = lastNeededCol;    
} 

ответ

0

Вы уверены, что это не потому, что дополнительная память используется, когда вы увеличиваете масштаб и просто кешируете для повышения производительности? Такие вещи, как UIImages, делают это, но будут корректно освобождаться, когда будут появляться предупреждения о памяти. Увеличение использования памяти не обязательно означает утечку, и даже не всегда желательно, чтобы использование памяти сокращалось до минимума. Heck, чаще всего, неиспользуемая память более расточительна, чем занятая память, но может быть освобождена в любое время для реального использования.

0

Во время жесты зажима (т. Е. Уменьшение), layoutSubviews в классе TiledScrollView приобретает большое количество плиток из-за того, как работает реализация (я измерил 70 плиток). Это приводит к огромному увеличению потребления памяти, которое вы наблюдаете.

Когда жест щепотка заканчивается, разрешение обновляется, что вызывает вызов reloadData. Теперь все плитки удаляются, помещаются в очередь многоразовых плит, а новый набор плиток берется из очереди многократного использования. Количество повторно используемых плит довольно низкое, поскольку для соответствия новому разрешению требуется не много фрагментов.

Это оставляет приложение в состоянии, когда многоразовая очередь содержит большое количество неиспользуемых плит (точнее, 64, потому что только 6 фрагментов были фактически использованы), таким образом тратя много памяти.

Одним из возможных решений было бы ограничить очередь многоразового черепицы на определенное максимальное число. Тем не менее, это не устраняет основной недостаток реализации layoutSubviews, из-за чего так много фрагментов приобретается во время защемления. Как бы то ни было, код всегда будет вызывать резкий всплеск потребления памяти во время защемления - за ним следует выпуск большей части памяти при сжатии концов, но только если вы ограничиваете многоразовую черепичную очередь.


EDIT

original demo code в настоящее время имеет статус "Пенсионер документа". Демо-код состоит из трех примерных проектов, вопрос относится к примеру «Tiling».

Смежные вопросы