/MapView/Map/RMTileCache.m

http://github.com/route-me/route-me · Objective C · 217 lines · 143 code · 40 blank · 34 comment · 33 complexity · 1a0ecc356806087fc1fd92fefc67cad7 MD5 · raw file

  1. //
  2. // RMTileCache.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 "RMTileCache.h"
  28. #import "RMMemoryCache.h"
  29. #import "RMDatabaseCache.h"
  30. #import "RMConfiguration.h"
  31. #import "RMTileSource.h"
  32. @interface RMTileCache ( Configuration )
  33. - (id<RMTileCache>) newMemoryCacheWithConfig: (NSDictionary*) cfg;
  34. - (id<RMTileCache>) newDatabaseCacheWithConfig: (NSDictionary*) cfg tileSource: (id<RMTileSource>) tileSource;
  35. @end
  36. @implementation RMTileCache
  37. -(id)initWithTileSource: (id<RMTileSource>) tileSource
  38. {
  39. if (![super init])
  40. return nil;
  41. caches = [[NSMutableArray alloc] init];
  42. id cacheCfg = [[RMConfiguration configuration] cacheConfiguration];
  43. if (cacheCfg==nil)
  44. {
  45. cacheCfg = [NSArray arrayWithObjects:
  46. /// \bug magic string literals
  47. [NSDictionary dictionaryWithObject: @"memory-cache" forKey: @"type"],
  48. [NSDictionary dictionaryWithObject: @"db-cache" forKey: @"type"],
  49. nil
  50. ];
  51. }
  52. for (id cfg in cacheCfg)
  53. {
  54. id<RMTileCache> newCache = nil;
  55. @try {
  56. NSString* type = [cfg valueForKey:@"type"];
  57. /// \bug magic string literals
  58. if ([@"memory-cache" isEqualToString: type])
  59. newCache = [self newMemoryCacheWithConfig: cfg];
  60. if ([@"db-cache" isEqualToString: type])
  61. newCache = [self newDatabaseCacheWithConfig: cfg tileSource: tileSource];
  62. if (newCache) {
  63. [caches addObject: newCache];
  64. [newCache release];
  65. } else {
  66. RMLog(@"failed to create cache of type %@", type);
  67. }
  68. }
  69. @catch (NSException * e) {
  70. RMLog(@"*** configuration error: %@", [e reason]);
  71. }
  72. }
  73. return self;
  74. }
  75. -(void) dealloc
  76. {
  77. [caches release];
  78. [super dealloc];
  79. }
  80. -(void)addCache: (id<RMTileCache>)cache
  81. {
  82. [caches addObject:cache];
  83. }
  84. +(NSNumber*) tileHash: (RMTile)tile
  85. {
  86. return [NSNumber numberWithUnsignedLongLong: RMTileKey(tile)];
  87. }
  88. // Returns the cached image if it exists. nil otherwise.
  89. -(RMTileImage*) cachedImage:(RMTile)tile
  90. {
  91. for (id<RMTileCache> cache in caches)
  92. {
  93. RMTileImage *image = [cache cachedImage:tile];
  94. if (image != nil)
  95. return image;
  96. }
  97. return nil;
  98. }
  99. -(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image
  100. {
  101. for (id<RMTileCache> cache in caches)
  102. {
  103. if ([cache respondsToSelector:@selector(addTile:WithImage:)])
  104. {
  105. [cache addTile:tile WithImage:image];
  106. }
  107. }
  108. }
  109. -(void)didReceiveMemoryWarning
  110. {
  111. LogMethod();
  112. for (id<RMTileCache> cache in caches)
  113. {
  114. [cache didReceiveMemoryWarning];
  115. }
  116. }
  117. -(void) removeAllCachedImages
  118. {
  119. for (id<RMTileCache> cache in caches)
  120. {
  121. [cache removeAllCachedImages];
  122. }
  123. }
  124. @end
  125. @implementation RMTileCache ( Configuration )
  126. /// \bug magic numbers and strings
  127. - (id<RMTileCache>) newMemoryCacheWithConfig: (NSDictionary*) cfg
  128. {
  129. NSNumber* capacity = [cfg objectForKey:@"capacity"];
  130. if (capacity == nil) capacity = [NSNumber numberWithInt: 32];
  131. return [[RMMemoryCache alloc] initWithCapacity: [capacity intValue]];
  132. }
  133. /// \bug magic numbers and strings
  134. - (id<RMTileCache>) newDatabaseCacheWithConfig: (NSDictionary*) cfg tileSource: (id<RMTileSource>) theTileSource
  135. {
  136. BOOL useCacheDir = NO;
  137. RMCachePurgeStrategy strategy = RMCachePurgeStrategyFIFO;
  138. /// \bug magic numbers
  139. NSUInteger capacity = 1000;
  140. NSUInteger minimalPurge = capacity / 10;
  141. NSNumber* capacityNumber = [cfg objectForKey:@"capacity"];
  142. if (capacityNumber!=nil) {
  143. NSInteger value = [capacityNumber intValue];
  144. // 0 is valid: it means no capacity limit
  145. if (value >= 0) {
  146. capacity = value;
  147. minimalPurge = MAX(1,capacity / 10);
  148. } else
  149. RMLog(@"illegal value for capacity: %d", value);
  150. }
  151. NSString* strategyStr = [cfg objectForKey:@"strategy"];
  152. if (strategyStr != nil) {
  153. if ([strategyStr caseInsensitiveCompare:@"FIFO"] == NSOrderedSame) strategy = RMCachePurgeStrategyFIFO;
  154. if ([strategyStr caseInsensitiveCompare:@"LRU"] == NSOrderedSame) strategy = RMCachePurgeStrategyLRU;
  155. }
  156. /// \bug magic string literals
  157. NSNumber* useCacheDirNumber = [cfg objectForKey:@"useCachesDirectory"];
  158. if (useCacheDirNumber!=nil) useCacheDir = [useCacheDirNumber boolValue];
  159. NSNumber* minimalPurgeNumber = [cfg objectForKey:@"minimalPurge"];
  160. if (minimalPurgeNumber != nil && capacity != 0) {
  161. NSUInteger value = [minimalPurgeNumber unsignedIntValue];
  162. if (value > 0 && value<=capacity)
  163. minimalPurge = value;
  164. else {
  165. RMLog(@"minimalPurge must be at least one and at most the cache capacity");
  166. }
  167. }
  168. RMDatabaseCache* dbCache = [[RMDatabaseCache alloc]
  169. initWithTileSource: theTileSource
  170. usingCacheDir: useCacheDir
  171. ];
  172. [dbCache setCapacity: capacity];
  173. [dbCache setPurgeStrategy: strategy];
  174. [dbCache setMinimalPurge: minimalPurge];
  175. return dbCache;
  176. }
  177. @end