Authored by Thomas Rasch

o Don't recreate the map view on tilesource changes (issue #47)

@@ -28,6 +28,8 @@ @@ -28,6 +28,8 @@
28 28
29 @property (nonatomic, assign) BOOL useSnapshotRenderer; 29 @property (nonatomic, assign) BOOL useSnapshotRenderer;
30 30
  31 +@property (nonatomic, readonly) id <RMTileSource> tileSource;
  32 +
31 - (id)initWithFrame:(CGRect)frame mapView:(RMMapView *)aMapView forTileSource:(id <RMTileSource>)aTileSource; 33 - (id)initWithFrame:(CGRect)frame mapView:(RMMapView *)aMapView forTileSource:(id <RMTileSource>)aTileSource;
32 34
33 @end 35 @end
@@ -21,12 +21,13 @@ @@ -21,12 +21,13 @@
21 21
22 @implementation RMMapTiledLayerView 22 @implementation RMMapTiledLayerView
23 { 23 {
24 - RMMapView *mapView;  
25 - id <RMTileSource> tileSource; 24 + RMMapView *_mapView;
  25 + id <RMTileSource> _tileSource;
26 } 26 }
27 27
28 -@synthesize delegate;  
29 -@synthesize useSnapshotRenderer; 28 +@synthesize delegate = _delegate;
  29 +@synthesize useSnapshotRenderer = _useSnapshotRenderer;
  30 +@synthesize tileSource = _tileSource;
30 31
31 + (Class)layerClass 32 + (Class)layerClass
32 { 33 {
@@ -43,8 +44,8 @@ @@ -43,8 +44,8 @@
43 if (!(self = [super initWithFrame:frame])) 44 if (!(self = [super initWithFrame:frame]))
44 return nil; 45 return nil;
45 46
46 - mapView = [aMapView retain];  
47 - tileSource = [aTileSource retain]; 47 + _mapView = [aMapView retain];
  48 + _tileSource = [aTileSource retain];
48 49
49 self.userInteractionEnabled = YES; 50 self.userInteractionEnabled = YES;
50 self.multipleTouchEnabled = YES; 51 self.multipleTouchEnabled = YES;
@@ -53,8 +54,8 @@ @@ -53,8 +54,8 @@
53 self.useSnapshotRenderer = NO; 54 self.useSnapshotRenderer = NO;
54 55
55 CATiledLayer *tiledLayer = [self tiledLayer]; 56 CATiledLayer *tiledLayer = [self tiledLayer];
56 - size_t levelsOf2xMagnification = mapView.tileSourcesContainer.maxZoom;  
57 - if (mapView.adjustTilesForRetinaDisplay) levelsOf2xMagnification += 1; 57 + size_t levelsOf2xMagnification = _mapView.tileSourcesContainer.maxZoom;
  58 + if (_mapView.adjustTilesForRetinaDisplay) levelsOf2xMagnification += 1;
58 tiledLayer.levelsOfDetail = levelsOf2xMagnification; 59 tiledLayer.levelsOfDetail = levelsOf2xMagnification;
59 tiledLayer.levelsOfDetailBias = levelsOf2xMagnification; 60 tiledLayer.levelsOfDetailBias = levelsOf2xMagnification;
60 61
@@ -85,10 +86,10 @@ @@ -85,10 +86,10 @@
85 86
86 - (void)dealloc 87 - (void)dealloc
87 { 88 {
88 - [tileSource cancelAllDownloads]; 89 + [_tileSource cancelAllDownloads];
89 self.layer.contents = nil; 90 self.layer.contents = nil;
90 - [tileSource release]; tileSource = nil;  
91 - [mapView release]; mapView = nil; 91 + [_tileSource release]; _tileSource = nil;
  92 + [_mapView release]; _mapView = nil;
92 [super dealloc]; 93 [super dealloc];
93 } 94 }
94 95
@@ -109,7 +110,7 @@ @@ -109,7 +110,7 @@
109 110
110 if (self.useSnapshotRenderer) 111 if (self.useSnapshotRenderer)
111 { 112 {
112 - zoom = (short)ceilf(mapView.adjustedZoomForRetinaDisplay); 113 + zoom = (short)ceilf(_mapView.adjustedZoomForRetinaDisplay);
113 CGFloat rectSize = bounds.size.width / powf(2.0, (float)zoom); 114 CGFloat rectSize = bounds.size.width / powf(2.0, (float)zoom);
114 115
115 int x1 = floor(rect.origin.x / rectSize), 116 int x1 = floor(rect.origin.x / rectSize),
@@ -119,7 +120,7 @@ @@ -119,7 +120,7 @@
119 120
120 // NSLog(@"Tiles from x1:%d, y1:%d to x2:%d, y2:%d @ zoom %d", x1, y1, x2, y2, zoom); 121 // NSLog(@"Tiles from x1:%d, y1:%d to x2:%d, y2:%d @ zoom %d", x1, y1, x2, y2, zoom);
121 122
122 - if (zoom >= tileSource.minZoom && zoom <= tileSource.maxZoom) 123 + if (zoom >= _tileSource.minZoom && zoom <= _tileSource.maxZoom)
123 { 124 {
124 UIGraphicsPushContext(context); 125 UIGraphicsPushContext(context);
125 126
@@ -127,7 +128,7 @@ @@ -127,7 +128,7 @@
127 { 128 {
128 for (int y=y1; y<=y2; ++y) 129 for (int y=y1; y<=y2; ++y)
129 { 130 {
130 - UIImage *tileImage = [tileSource imageForTile:RMTileMake(x, y, zoom) inCache:[mapView tileCache]]; 131 + UIImage *tileImage = [_tileSource imageForTile:RMTileMake(x, y, zoom) inCache:[_mapView tileCache]];
131 [tileImage drawInRect:CGRectMake(x * rectSize, y * rectSize, rectSize, rectSize)]; 132 [tileImage drawInRect:CGRectMake(x * rectSize, y * rectSize, rectSize, rectSize)];
132 } 133 }
133 } 134 }
@@ -146,12 +147,12 @@ @@ -146,12 +147,12 @@
146 147
147 UIImage *tileImage = nil; 148 UIImage *tileImage = nil;
148 149
149 - if (zoom >= tileSource.minZoom && zoom <= tileSource.maxZoom)  
150 - tileImage = [tileSource imageForTile:RMTileMake(x, y, zoom) inCache:[mapView tileCache]]; 150 + if (zoom >= _tileSource.minZoom && zoom <= _tileSource.maxZoom)
  151 + tileImage = [_tileSource imageForTile:RMTileMake(x, y, zoom) inCache:[_mapView tileCache]];
151 152
152 if ( ! tileImage) 153 if ( ! tileImage)
153 { 154 {
154 - if (mapView.missingTilesDepth == 0) 155 + if (_mapView.missingTilesDepth == 0)
155 { 156 {
156 tileImage = [RMTileImage errorTile]; 157 tileImage = [RMTileImage errorTile];
157 } 158 }
@@ -160,14 +161,14 @@ @@ -160,14 +161,14 @@
160 NSUInteger currentTileDepth = 1, currentZoom = zoom - currentTileDepth; 161 NSUInteger currentTileDepth = 1, currentZoom = zoom - currentTileDepth;
161 162
162 // tries to return lower zoom level tiles if a tile cannot be found 163 // tries to return lower zoom level tiles if a tile cannot be found
163 - while ( !tileImage && currentZoom >= tileSource.minZoom && currentTileDepth <= mapView.missingTilesDepth) 164 + while ( !tileImage && currentZoom >= _tileSource.minZoom && currentTileDepth <= _mapView.missingTilesDepth)
164 { 165 {
165 float nextX = x / powf(2.0, (float)currentTileDepth), 166 float nextX = x / powf(2.0, (float)currentTileDepth),
166 nextY = y / powf(2.0, (float)currentTileDepth); 167 nextY = y / powf(2.0, (float)currentTileDepth);
167 float nextTileX = floor(nextX), 168 float nextTileX = floor(nextX),
168 nextTileY = floor(nextY); 169 nextTileY = floor(nextY);
169 170
170 - tileImage = [tileSource imageForTile:RMTileMake((int)nextTileX, (int)nextTileY, currentZoom) inCache:[mapView tileCache]]; 171 + tileImage = [_tileSource imageForTile:RMTileMake((int)nextTileX, (int)nextTileY, currentZoom) inCache:[_mapView tileCache]];
171 172
172 if (tileImage) 173 if (tileImage)
173 { 174 {
@@ -192,7 +193,7 @@ @@ -192,7 +193,7 @@
192 } 193 }
193 } 194 }
194 195
195 - if (mapView.debugTiles) 196 + if (_mapView.debugTiles)
196 { 197 {
197 UIGraphicsBeginImageContext(tileImage.size); 198 UIGraphicsBeginImageContext(tileImage.size);
198 199
@@ -238,34 +239,34 @@ @@ -238,34 +239,34 @@
238 239
239 - (void)handleSingleTap:(UIGestureRecognizer *)recognizer 240 - (void)handleSingleTap:(UIGestureRecognizer *)recognizer
240 { 241 {
241 - if ([delegate respondsToSelector:@selector(mapTiledLayerView:singleTapAtPoint:)])  
242 - [delegate mapTiledLayerView:self singleTapAtPoint:[recognizer locationInView:mapView]]; 242 + if ([_delegate respondsToSelector:@selector(mapTiledLayerView:singleTapAtPoint:)])
  243 + [_delegate mapTiledLayerView:self singleTapAtPoint:[recognizer locationInView:_mapView]];
243 } 244 }
244 245
245 - (void)handleTwoFingerSingleTap:(UIGestureRecognizer *)recognizer 246 - (void)handleTwoFingerSingleTap:(UIGestureRecognizer *)recognizer
246 { 247 {
247 - if ([delegate respondsToSelector:@selector(mapTiledLayerView:twoFingerSingleTapAtPoint:)])  
248 - [delegate mapTiledLayerView:self twoFingerSingleTapAtPoint:[recognizer locationInView:mapView]]; 248 + if ([_delegate respondsToSelector:@selector(mapTiledLayerView:twoFingerSingleTapAtPoint:)])
  249 + [_delegate mapTiledLayerView:self twoFingerSingleTapAtPoint:[recognizer locationInView:_mapView]];
249 } 250 }
250 251
251 - (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer 252 - (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer
252 { 253 {
253 if (recognizer.state != UIGestureRecognizerStateBegan) return; 254 if (recognizer.state != UIGestureRecognizerStateBegan) return;
254 255
255 - if ([delegate respondsToSelector:@selector(mapTiledLayerView:longPressAtPoint:)])  
256 - [delegate mapTiledLayerView:self longPressAtPoint:[recognizer locationInView:mapView]]; 256 + if ([_delegate respondsToSelector:@selector(mapTiledLayerView:longPressAtPoint:)])
  257 + [_delegate mapTiledLayerView:self longPressAtPoint:[recognizer locationInView:_mapView]];
257 } 258 }
258 259
259 - (void)handleDoubleTap:(UIGestureRecognizer *)recognizer 260 - (void)handleDoubleTap:(UIGestureRecognizer *)recognizer
260 { 261 {
261 - if ([delegate respondsToSelector:@selector(mapTiledLayerView:doubleTapAtPoint:)])  
262 - [delegate mapTiledLayerView:self doubleTapAtPoint:[recognizer locationInView:mapView]]; 262 + if ([_delegate respondsToSelector:@selector(mapTiledLayerView:doubleTapAtPoint:)])
  263 + [_delegate mapTiledLayerView:self doubleTapAtPoint:[recognizer locationInView:_mapView]];
263 } 264 }
264 265
265 - (void)handleTwoFingerDoubleTap:(UIGestureRecognizer *)recognizer 266 - (void)handleTwoFingerDoubleTap:(UIGestureRecognizer *)recognizer
266 { 267 {
267 - if ([delegate respondsToSelector:@selector(mapTiledLayerView:twoFingerDoubleTapAtPoint:)])  
268 - [delegate mapTiledLayerView:self twoFingerDoubleTapAtPoint:[recognizer locationInView:mapView]]; 268 + if ([_delegate respondsToSelector:@selector(mapTiledLayerView:twoFingerDoubleTapAtPoint:)])
  269 + [_delegate mapTiledLayerView:self twoFingerDoubleTapAtPoint:[recognizer locationInView:_mapView]];
269 } 270 }
270 271
271 @end 272 @end
@@ -1411,7 +1411,30 @@ @@ -1411,7 +1411,30 @@
1411 [self setZoom:[self zoom]]; // setZoom clamps zoom level to min/max limits 1411 [self setZoom:[self zoom]]; // setZoom clamps zoom level to min/max limits
1412 1412
1413 // Recreate the map layer 1413 // Recreate the map layer
1414 - [self createMapView]; 1414 + NSUInteger tileSourcesContainerSize = [[_tileSourcesContainer tileSources] count];
  1415 +
  1416 + if (tileSourcesContainerSize == 1)
  1417 + {
  1418 + [self createMapView];
  1419 + }
  1420 + else
  1421 + {
  1422 + int tileSideLength = [_tileSourcesContainer tileSideLength];
  1423 + CGSize contentSize = CGSizeMake(tileSideLength, tileSideLength); // zoom level 1
  1424 +
  1425 + RMMapTiledLayerView *tiledLayerView = [[RMMapTiledLayerView alloc] initWithFrame:CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) mapView:self forTileSource:newTileSource];
  1426 + tiledLayerView.delegate = self;
  1427 +
  1428 + if (self.adjustTilesForRetinaDisplay && _screenScale > 1.0)
  1429 + ((CATiledLayer *)tiledLayerView.layer).tileSize = CGSizeMake(tileSideLength * 2.0, tileSideLength * 2.0);
  1430 + else
  1431 + ((CATiledLayer *)tiledLayerView.layer).tileSize = CGSizeMake(tileSideLength, tileSideLength);
  1432 +
  1433 + if (index >= [[_tileSourcesContainer tileSources] count])
  1434 + [_tiledLayersSuperview addSubview:tiledLayerView];
  1435 + else
  1436 + [_tiledLayersSuperview insertSubview:tiledLayerView atIndex:index];
  1437 + }
1415 1438
1416 [self setCenterProjectedPoint:centerPoint animated:NO]; 1439 [self setCenterProjectedPoint:centerPoint animated:NO];
1417 } 1440 }
@@ -1429,8 +1452,20 @@ @@ -1429,8 +1452,20 @@
1429 _constrainMovement = NO; 1452 _constrainMovement = NO;
1430 } 1453 }
1431 1454
1432 - // Recreate the map layer  
1433 - [self createMapView]; 1455 + // Remove the map layer
  1456 + RMMapTiledLayerView *tileSourceTiledLayerView = nil;
  1457 +
  1458 + for (RMMapTiledLayerView *tiledLayerView in _tiledLayersSuperview.subviews)
  1459 + {
  1460 + if (tiledLayerView.tileSource == tileSource)
  1461 + {
  1462 + tileSourceTiledLayerView = tiledLayerView;
  1463 + break;
  1464 + }
  1465 + }
  1466 +
  1467 + tileSourceTiledLayerView.layer.contents = nil;
  1468 + [tileSourceTiledLayerView removeFromSuperview]; [tileSourceTiledLayerView release]; tileSourceTiledLayerView = nil;
1434 1469
1435 [self setCenterProjectedPoint:centerPoint animated:NO]; 1470 [self setCenterProjectedPoint:centerPoint animated:NO];
1436 } 1471 }
@@ -1448,20 +1483,29 @@ @@ -1448,20 +1483,29 @@
1448 _constrainMovement = NO; 1483 _constrainMovement = NO;
1449 } 1484 }
1450 1485
1451 - // Recreate the map layer  
1452 - [self createMapView]; 1486 + // Remove the map layer
  1487 + RMMapTiledLayerView *tileSourceTiledLayerView = [_tiledLayersSuperview.subviews objectAtIndex:index];
  1488 +
  1489 + tileSourceTiledLayerView.layer.contents = nil;
  1490 + [tileSourceTiledLayerView removeFromSuperview]; [tileSourceTiledLayerView release]; tileSourceTiledLayerView = nil;
1453 1491
1454 [self setCenterProjectedPoint:centerPoint animated:NO]; 1492 [self setCenterProjectedPoint:centerPoint animated:NO];
1455 } 1493 }
1456 1494
1457 - (void)moveTileSourceAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex 1495 - (void)moveTileSourceAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex
1458 { 1496 {
  1497 + if (fromIndex == toIndex)
  1498 + return;
  1499 +
  1500 + if (fromIndex >= [[_tileSourcesContainer tileSources] count])
  1501 + return;
  1502 +
1459 RMProjectedPoint centerPoint = [self centerProjectedPoint]; 1503 RMProjectedPoint centerPoint = [self centerProjectedPoint];
1460 1504
1461 [_tileSourcesContainer moveTileSourceAtIndex:fromIndex toIndex:toIndex]; 1505 [_tileSourcesContainer moveTileSourceAtIndex:fromIndex toIndex:toIndex];
1462 1506
1463 - // Recreate the map layer  
1464 - [self createMapView]; 1507 + // Move the map layer
  1508 + [_tiledLayersSuperview exchangeSubviewAtIndex:fromIndex withSubviewAtIndex:toIndex];
1465 1509
1466 [self setCenterProjectedPoint:centerPoint animated:NO]; 1510 [self setCenterProjectedPoint:centerPoint animated:NO];
1467 } 1511 }
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 #import "RMAnnotation.h" 17 #import "RMAnnotation.h"
18 #import "RMQuadTree.h" 18 #import "RMQuadTree.h"
19 #import "RMCoordinateGridSource.h" 19 #import "RMCoordinateGridSource.h"
  20 +#import "RMOpenCycleMapSource.h"
20 21
21 @implementation MainViewController 22 @implementation MainViewController
22 { 23 {
@@ -170,16 +171,21 @@ @@ -170,16 +171,21 @@
170 171
171 // double delayInSeconds = 5.0; 172 // double delayInSeconds = 5.0;
172 // dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 173 // dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
173 -// dispatch_after(popTime, dispatch_get_main_queue(), ^(void){  
174 -// [mapView addTileSource:[[[RMOpenSeaMapLayer alloc] init] autorelease]]; 174 +// dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
  175 +// [mapView addTileSource:[[[RMCoordinateGridSource alloc] init] autorelease]];
175 // 176 //
176 // dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 177 // dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
177 -// dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 178 +// dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
178 // [mapView setHidden:YES forTileSourceAtIndex:1]; 179 // [mapView setHidden:YES forTileSourceAtIndex:1];
179 // 180 //
180 // dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 181 // dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
181 -// dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 182 +// dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
182 // [mapView setHidden:NO forTileSourceAtIndex:1]; 183 // [mapView setHidden:NO forTileSourceAtIndex:1];
  184 +//
  185 +// dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
  186 +// dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
  187 +// [mapView removeTileSourceAtIndex:1];
  188 +// });
183 // }); 189 // });
184 // }); 190 // });
185 // }); 191 // });