PageRenderTime 43ms CodeModel.GetById 21ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/MapView/Map/RMMemoryCache.m

http://github.com/route-me/route-me
Objective C | 138 lines | 81 code | 25 blank | 32 comment | 9 complexity | 1d5b7489d624e4d4cdb0e08b67a8c845 MD5 | raw file
  1//
  2//  RMMemoryCache.m
  3//
  4// Copyright (c) 2008-2009, Route-Me Contributors
  5// All rights reserved.
  6//
  7// Redistribution and use in source and binary forms, with or without
  8// modification, are permitted provided that the following conditions are met:
  9//
 10// * Redistributions of source code must retain the above copyright notice, this
 11//   list of conditions and the following disclaimer.
 12// * Redistributions in binary form must reproduce the above copyright notice,
 13//   this list of conditions and the following disclaimer in the documentation
 14//   and/or other materials provided with the distribution.
 15//
 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 17// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 19// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 20// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 21// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 22// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 23// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 24// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 25// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 26// POSSIBILITY OF SUCH DAMAGE.
 27
 28#import "RMMemoryCache.h"
 29#import "RMTileImage.h"
 30
 31@implementation RMMemoryCache
 32
 33-(id)initWithCapacity: (NSUInteger) _capacity
 34{
 35	if (![super init])
 36		return nil;
 37
 38	RMLog(@"initializing memory cache %@ with capacity %d", self, _capacity);
 39	
 40	cache = [[NSMutableDictionary alloc] initWithCapacity:_capacity];
 41	
 42	if (_capacity < 1)
 43		_capacity = 1;
 44	capacity = _capacity;
 45	
 46	[[NSNotificationCenter defaultCenter] addObserver:self
 47											 selector:@selector(imageLoadingCancelled:)
 48												 name:RMMapImageLoadingCancelledNotification
 49											   object:nil];
 50	
 51	return self;
 52}
 53
 54/// \bug magic number
 55-(id)init
 56{
 57	return [self initWithCapacity:32];
 58}
 59
 60-(void) dealloc
 61{
 62	LogMethod();
 63	[[NSNotificationCenter defaultCenter] removeObserver:self];
 64	[cache release];
 65	[super dealloc];
 66}
 67
 68-(void) didReceiveMemoryWarning
 69{
 70	LogMethod();		
 71	[cache removeAllObjects];
 72}
 73
 74-(void) removeTile: (RMTile) tile
 75{
 76//	RMLog(@"tile %d %d %d removed from cache", tile.x, tile.y, tile.zoom);
 77	[cache removeObjectForKey:[RMTileCache tileHash: tile]];
 78}
 79
 80-(void) imageLoadingCancelled: (NSNotification*)notification
 81{
 82	[self removeTile: [[notification object] tile]];
 83}
 84
 85-(RMTileImage*) cachedImage:(RMTile)tile
 86{
 87	NSNumber *key = [RMTileCache tileHash: tile];
 88	RMTileImage *image = [cache objectForKey:key];
 89	return image;
 90}
 91
 92/// Remove the least-recently used image from cache, if cache is at or over capacity. Removes only 1 image.
 93-(void)makeSpaceInCache
 94{
 95	while ([cache count] >= capacity)
 96	{
 97		// Rather than scanning I would really like to be using a priority queue
 98		// backed by a heap here.
 99		
100		NSEnumerator *enumerator = [cache objectEnumerator];
101		RMTileImage *image;
102		
103		NSDate *oldestDate = nil;
104		RMTileImage *oldestImage = nil;
105		
106		while ((image = (RMTileImage*)[enumerator nextObject]))
107		{
108			if (oldestDate == nil
109				|| ([oldestDate timeIntervalSinceReferenceDate] > [[image lastUsedTime] timeIntervalSinceReferenceDate]))
110			{
111				oldestDate = [image lastUsedTime];
112				oldestImage = image;
113			}
114		}
115		
116		if(oldestImage) [self removeTile:[oldestImage tile]];
117	}
118}
119
120-(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image
121{
122	if (RMTileIsDummy(tile))
123		return;
124	
125	//	RMLog(@"cache add %@", key);
126
127	[self makeSpaceInCache];
128	
129	NSNumber *key = [RMTileCache tileHash: tile];
130	[cache setObject:image forKey:key];
131}
132
133-(void) removeAllCachedImages 
134{
135	[cache removeAllObjects];
136}
137
138@end