地图控件MKMapView由于要从网络上加载地图数据并在内存中缓存,因此通常占用的内存开销特别大,特别是当用户进行放大缩小、快速拖动、3d旋转时,内存基本呈直线上升,单个地图控件占用百兆内存不成问题。
假设在一个UITableView中,每个Cell的宽度和高度分别为320、150,每个Cell中都放置一个高度为320*150的MkMapView,采用Cell重用的方式,这种情况下iPhone 4s上UITableView中将最多包含4个MkMapView。又假设这里的MkMapView仅仅用于展示,不接受用户操作,此时我们保守估计每个 MkMapView占用10M内存。基于上述两种假设,不难算出,此时地图控件占用的总内存大小为40M = 4 * 10M。40M的内存对于移动应用开发,可以算是巨大的开销了。
针对这种情况,我们提出截图的方案来有效解决这个问题。举个例子,假设UITableView显示的内容如下:
第一行:北京市地图
第二行:上海市地图
第三行:广州市地图
第四行:深圳市地图
。。。。。。。。。
第N行:某某市的地图
解决方法就是:每一行的地图在头一次加载时,当地图数据加载完成后,将该地图截图保存为图片,等列表再次滚动到该行,我们用对应的图片来替代之前的地图。下面我们来说一下详细的实现步骤。
一、截图时机
通常我们在使用MKMapView地图控件时,如常用的运动的APP,会在地图上添加一些大头针(MKAnnotation)和绘制一些线条(MKOverlay)。如果你的地图控件添加了大头针以及绘制了线条,那么正确的截图时机应该满足如下三个要求:1、地图数据加载完成;2、大头针绘制完成;3、线条绘制完成。
经过分析,地图数据加载、大头针绘制以及线条绘制都是异步过程, 那么问题来了,如何判断上述三种操作已完成?没错,MkMapViewDelegate提供了相应的方法,分别对应的方法为:
地图数据加载完成:
大头针绘制完成:
线条绘制完成:
二、地图截图
地图控件继承于UIView,截图的方法这里就不细讲了,直接上代码:
+ (UIImage *) imageWithUIView:(UIView *)view
{
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [[UIScreen mainScreen] scale]);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
三、保存图片
保存图片时,注意图片的命名,保证图片能够对应上相应的MKMapView,如:北京.png,上海.png,广州.png,等等。保存图片的代码如下:
+ (BOOL)saveImage:(UIImage*)image WithName:(NSString*)imageName
{
NSString *imageDir = [self getDir];
NSString *imagePath = [imageDir stringByAppendingPathComponent:imageName];
BOOL isCreated = [UIImagePNGRepresentation(image) writeToFile:imagePath options:NSAtomicWrite error:nil];
return isCreated;
}
四、整体实现
- (void)doScreenshot
{
if (_isDrawAnnotationsDone && _isRenderMapDone && _isDrawOverlayDone) {
UIImage *mapImage = [self imageWithUIView:_mapView];
[self saveImage:mapImage WithName:@"xx.png"];
}
}
- (void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered
{
_isRenderMapDone = YES;
[self doScreenshot];
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
_isDrawAnnotationsDone = YES;
[self doScreenshot];
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{
_isDrawOverlayDone = YES;
[self doScreenshot];
}
转载请标明原文出处!!!