/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. #import "RMMemoryCache.h"
  28. #import "RMTileImage.h"
  29. @implementation RMMemoryCache
  30. -(id)initWithCapacity: (NSUInteger) _capacity
  31. {
  32. if (![super init])
  33. return nil;
  34. RMLog(@"initializing memory cache %@ with capacity %d", self, _capacity);
  35. cache = [[NSMutableDictionary alloc] initWithCapacity:_capacity];
  36. if (_capacity < 1)
  37. _capacity = 1;
  38. capacity = _capacity;
  39. [[NSNotificationCenter defaultCenter] addObserver:self
  40. selector:@selector(imageLoadingCancelled:)
  41. name:RMMapImageLoadingCancelledNotification
  42. object:nil];
  43. return self;
  44. }
  45. /// \bug magic number
  46. -(id)init
  47. {
  48. return [self initWithCapacity:32];
  49. }
  50. -(void) dealloc
  51. {
  52. LogMethod();
  53. [[NSNotificationCenter defaultCenter] removeObserver:self];
  54. [cache release];
  55. [super dealloc];
  56. }
  57. -(void) didReceiveMemoryWarning
  58. {
  59. LogMethod();
  60. [cache removeAllObjects];
  61. }
  62. -(void) removeTile: (RMTile) tile
  63. {
  64. // RMLog(@"tile %d %d %d removed from cache", tile.x, tile.y, tile.zoom);
  65. [cache removeObjectForKey:[RMTileCache tileHash: tile]];
  66. }
  67. -(void) imageLoadingCancelled: (NSNotification*)notification
  68. {
  69. [self removeTile: [[notification object] tile]];
  70. }
  71. -(RMTileImage*) cachedImage:(RMTile)tile
  72. {
  73. NSNumber *key = [RMTileCache tileHash: tile];
  74. RMTileImage *image = [cache objectForKey:key];
  75. return image;
  76. }
  77. /// Remove the least-recently used image from cache, if cache is at or over capacity. Removes only 1 image.
  78. -(void)makeSpaceInCache
  79. {
  80. while ([cache count] >= capacity)
  81. {
  82. // Rather than scanning I would really like to be using a priority queue
  83. // backed by a heap here.
  84. NSEnumerator *enumerator = [cache objectEnumerator];
  85. RMTileImage *image;
  86. NSDate *oldestDate = nil;
  87. RMTileImage *oldestImage = nil;
  88. while ((image = (RMTileImage*)[enumerator nextObject]))
  89. {
  90. if (oldestDate == nil
  91. || ([oldestDate timeIntervalSinceReferenceDate] > [[image lastUsedTime] timeIntervalSinceReferenceDate]))
  92. {
  93. oldestDate = [image lastUsedTime];
  94. oldestImage = image;
  95. }
  96. }
  97. if(oldestImage) [self removeTile:[oldestImage tile]];
  98. }
  99. }
  100. -(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image
  101. {
  102. if (RMTileIsDummy(tile))
  103. return;
  104. // RMLog(@"cache add %@", key);
  105. [self makeSpaceInCache];
  106. NSNumber *key = [RMTileCache tileHash: tile];
  107. [cache setObject:image forKey:key];
  108. }
  109. -(void) removeAllCachedImages
  110. {
  111. [cache removeAllObjects];
  112. }
  113. @end