There is problem in ScrollViewSuite. it use more memory than needed . for example:
- Load image in 25% and measure memory (4 MB)
- Zoom in image to 100% and measure memory (30 MB)
- Zoom out to 25% and measure memory (30 MB) - why 30 ? it must use only 4 MB - that is the probl开发者_运维技巧em.
How to fix the problem ?
/***********************************************************************************/
/* 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;
}
Are you sure that it isn't because extra memory is being used when you zoom in and just cached off for increased performance? Things such as UIImages do such, but will release correctly when memory warnings start hitting. Increased memory usage does not necessarily mean leakage, nor is it always even desirable for memory usage to shrink down to the minimum possible. Heck, more often than not, unused memory is more wasteful than memory that's occupied but can be deallocated at any time for real usage.
During the pinch gesture (i.e. zoom out), layoutSubviews
in the TiledScrollView
class acquires a large number of tiles due to the way how the implementation works (I measured 70 tiles). This causes the huge increase in memory consumption that you observed.
When the pinch gesture ends, the resolution is updated, which triggers a call to reloadData
. All tiles are now removed, placed into the queue of reusable tiles, and a new set of tiles is taken from the reusable queue. The number of reused tiles is quite low because not many tiles are needed to match the new resolution.
This leaves the application in a state where the reusable queue holds a large number of unused tiles (64 to be precise, because only 6 tiles were actually reused), thus wasting a lot of memory.
One possible solution would be to limit the reusable tile queue to a certain maximum number. However, this does not fix the basic flaw of the layoutSubviews
implementation which causes so many tiles to be acquired during pinching. As it stands, the code will always cause a sharp spike of memory consumption during pinching - followed by a release of most of the memory when pinching ends, but only if you limit the reusable tile queue.
EDIT
The original demo code nowadays has the status "Retired document". The demo code consists of three example projects, the question refers to the "Tiling" example.
精彩评论