2010-11-30 44 views
1

ScrollViewSuite有問題。它使用的內存比需要的多。 例如:ScrollViewSuite示例代碼使用比所需內存更多的內存?

  1. 加載圖像中25%和測量存儲器(4 MB)
  2. 放大圖像爲100%,並測量存儲器(30 MB)
  3. 縮小到25%,並測量存儲器( 30 MB) - 爲什麼30?它只能使用4 MB - 這是問題所在。

如何解決問題?

/***********************************************************************************/ 
/* 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這樣的事情,但是當內存警告開始擊中時會正確釋放。增加的內存使用量不一定意味着泄漏,也不總是希望內存使用量儘可能縮小。哎呀,多數情況下,未使用的內存比已佔用的內存更浪費,但可以隨時取消分配以供實際使用。

0

在擠壓手勢(即縮小)期間,TiledScrollView類中的layoutSubviews由於實現如何工作的方式(我測量了70個圖塊)而獲取大量圖塊。這會導致您觀察到的內存消耗的巨大增加。

捏合手勢結束時,分辨率被更新,觸發對reloadData的呼叫。所有瓷磚現在都被移除,放入可重用瓷磚的隊列中,並從可重用的隊列中取出一組新的瓷磚。重用瓷磚的數量非常低,因爲不需要很多瓷磚來匹配新的分辨率。

這使得應用程序處於可重用隊列中持有大量未使用的tile的狀態(準確地說64個,因爲實際上只重用了6個tile),因此浪費了大量內存。

一種可能的解決方案是將可重用瓦片隊列限制到某個最大數量。然而,這並沒有解決實施過程中的基本缺陷,這會導致在捏過程中獲得很多瓷磚。就目前而言,代碼在捏縮時總是會導致內存消耗的尖峯 - 隨後在捏結束時釋放大部分內存,但前提是限制可重用瓦片隊列。


編輯

original demo code現在的狀態爲 「退休的文件」。演示代碼由三個示例項目組成,問題涉及「平鋪」示例。