/MapView/Map/RMDatabaseCache.m

http://github.com/route-me/route-me · Objective C · 190 lines · 118 code · 38 blank · 34 comment · 16 complexity · 2cb7331854a4efed86c4af32203d69b6 MD5 · raw file

  1. //
  2. // RMDatabaseCache.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 "RMDatabaseCache.h"
  28. #import "RMTileCacheDAO.h"
  29. #import "RMTileImage.h"
  30. #import "RMTile.h"
  31. @implementation RMDatabaseCache
  32. @synthesize databasePath;
  33. + (NSString*)dbPathForTileSource: (id<RMTileSource>) source usingCacheDir: (BOOL) useCacheDir
  34. {
  35. NSArray *paths;
  36. if (useCacheDir) {
  37. paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
  38. } else {
  39. paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  40. }
  41. if ([paths count] > 0) // Should only be one...
  42. {
  43. NSString *cachePath = [paths objectAtIndex:0];
  44. // check for existence of cache directory
  45. if ( ![[NSFileManager defaultManager] fileExistsAtPath: cachePath])
  46. {
  47. // create a new cache directory
  48. [[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:nil];
  49. }
  50. /// \bug magic string literals
  51. NSString *filename = [NSString stringWithFormat:@"Map%@.sqlite", [source uniqueTilecacheKey]];
  52. return [cachePath stringByAppendingPathComponent:filename];
  53. }
  54. return nil;
  55. }
  56. -(id) initWithDatabase: (NSString*)path
  57. {
  58. if (![super init])
  59. return nil;
  60. self.databasePath = path;
  61. dao = [[RMTileCacheDAO alloc] initWithDatabase:path];
  62. if (dao == nil)
  63. return nil;
  64. return self;
  65. }
  66. -(id) initWithTileSource: (id<RMTileSource>) source usingCacheDir: (BOOL) useCacheDir
  67. {
  68. return [self initWithDatabase:[RMDatabaseCache dbPathForTileSource:source usingCacheDir: useCacheDir]];
  69. }
  70. -(void) dealloc
  71. {
  72. [[NSNotificationCenter defaultCenter] removeObserver:self];
  73. [databasePath release];
  74. [dao release];
  75. [super dealloc];
  76. }
  77. -(void) setPurgeStrategy: (RMCachePurgeStrategy) theStrategy
  78. {
  79. purgeStrategy = theStrategy;
  80. }
  81. -(void) setCapacity: (NSUInteger) theCapacity
  82. {
  83. capacity = theCapacity;
  84. }
  85. -(void) setMinimalPurge: (NSUInteger) theMinimalPurge
  86. {
  87. minimalPurge = theMinimalPurge;
  88. }
  89. -(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image
  90. {
  91. // The tile probably hasn't loaded any data yet... we must be patient.
  92. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addImageData:) name:RMMapImageLoadedNotification object:image];
  93. }
  94. -(void) addImageData: (NSNotification *)notification
  95. {
  96. NSData *data = [[notification userInfo] objectForKey:@"data"];
  97. /// \bug magic string literals
  98. RMTileImage *image = (RMTileImage*)[notification object];
  99. @synchronized (self) {
  100. if (capacity != 0) {
  101. NSUInteger tilesInDb = [dao count];
  102. if (capacity <= tilesInDb) {
  103. [dao purgeTiles: MAX(minimalPurge, 1+tilesInDb-capacity)];
  104. }
  105. }
  106. NSDate *lastUsedTime = [[image lastUsedTime] retain];
  107. [dao addData:data LastUsed: lastUsedTime ForTile:RMTileKey([image tile])];
  108. [lastUsedTime release]; lastUsedTime = nil;
  109. }
  110. [[NSNotificationCenter defaultCenter] removeObserver:self
  111. name:RMMapImageLoadedNotification
  112. object:image];
  113. // RMLog(@"%d items in DB", [dao count]);
  114. }
  115. -(RMTileImage*) cachedImage:(RMTile)tile
  116. {
  117. // RMLog(@"Looking for cached image in DB");
  118. NSData *data = nil;
  119. @synchronized (self) {
  120. data = [dao dataForTile:RMTileKey(tile)];
  121. if (data == nil)
  122. return nil;
  123. if (capacity != 0 && purgeStrategy == RMCachePurgeStrategyLRU) {
  124. [dao touchTile: RMTileKey(tile) withDate: [NSDate date]];
  125. }
  126. }
  127. RMTileImage *image = [RMTileImage imageForTile:tile withData:data];
  128. // RMLog(@"DB cache hit for tile %d %d %d", tile.x, tile.y, tile.zoom);
  129. return image;
  130. }
  131. -(void) purgeTilesFromBefore: (NSDate*) date
  132. {
  133. @synchronized(self)
  134. {
  135. [dao purgeTilesFromBefore:date];
  136. }
  137. }
  138. -(void)didReceiveMemoryWarning
  139. {
  140. @synchronized(self)
  141. {
  142. [dao didReceiveMemoryWarning];
  143. }
  144. }
  145. -(void) removeAllCachedImages
  146. {
  147. @synchronized(self)
  148. {
  149. [dao removeAllCachedImages];
  150. }
  151. }
  152. @end