ScrollViewSuite示例代码使用的内存多于必要的内存?

时间:2010-11-30 20:04:39

标签: iphone uiscrollview

ScrollViewSuite存在问题。它使用的内存比需要的多。 例如:

  1. 将图像加载到25%并测量内存(4 MB)
  2. 将图像放大至100%并测量内存(30 MB)
  3. 缩小到25%并测量内存(30 MB) - 为什么30?它必须只使用4 MB - 这就是问题。
  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;            
    }
    

2 个答案:

答案 0 :(得分:0)

你确定它不是因为你在放大时只使用额外的内存而只是缓存以提高性能吗?诸如UIImages之类的东西会这样做,但会在内存警告开始命中时正确释放。增加内存使用量并不一定意味着泄漏,也不总是希望将内存使用量缩减到可能的最小值。哎呀,通常情况下,未使用的内存比占用的内存更浪费,但可以随时解除分配以供实际使用。

答案 1 :(得分:0)

在捏合手势(即缩小)期间,由于实现的工作方式(我测量了70个图块),layoutSubviews类中的TiledScrollView获取了大量图块。这会导致您观察到的内存消耗量大幅增加。

当捏合手势结束时,分辨率会更新,从而触发对reloadData的调用。现在移除所有切片,将其放入可重复使用的切片队列中,并从可重复使用的队列中获取一组新切片。重复使用的磁贴数量非常少,因为匹配新分辨率所需的磁贴数量不多。

这使得应用程序处于可重用队列中包含大量未使用的块的状态(准确地说是64,因为实际上只重用了6个块),从而浪费了大量内存。

一种可能的解决方案是将可重复使用的磁贴队列限制为某个最大数量。但是,这并没有解决layoutSubviews实现的基本缺陷,这会导致在压缩期间获取如此多的切片。目前,代码将总是在pinching期间导致内存消耗急剧增加 - 然后在pinching结束时释放大部分内存,但前提是限制可重用的tile队列。


修改

现在original demo code的状态为#34;退休文件&#34;。演示代码由三个示例项目组成,问题涉及&#34; Tiling&#34;示例