標籤:
地圖控制項MKMapView由於要從網路上載入地圖資料並在記憶體中緩衝,因此通常佔用的記憶體開銷特別大,特別是當使用者進行放大縮小、快速拖動、3d旋轉時,記憶體基本呈直線上升,單個地圖控制項佔用百兆記憶體不成問題。
假設在一個UITableView中,每個Cell的寬度和高度分別為320、150,每個Cell中都放置一個高度為320*150的MkMapView,採用Cell重用的方式,這種情況下iPhone 4s上UITableView中將最多包含4個MkMapView。又假設這裡的MkMapView僅僅用於展示,不接受使用者操作,此時我們保守估計每個 MkMapView佔用10M記憶體。基於上述兩種假設,不難算出,此時地圖控制項佔用的總記憶體大小為40M = 4 * 10M。40M的記憶體對於行動裝置 App開發,可以算是巨大的開銷了。
針對這種情況,我們提出的方案來有效解決這個問題。舉個例子,假設UITableView顯示的內容如下:
第一行:北京市地圖
第二行:上海市地圖
第三行:廣州市地圖
第四行:深圳市地圖
。。。。。。。。。
第N行:某某市的地圖
解決方案就是:每一行的地圖在頭一次載入時,當地圖資料載入完成後,將該地圖儲存為圖片,等列表再次滾動到該行,我們用對應的圖片來替代之間的地圖。下面我們來說一下詳細的實現步驟。
一、時機
通常我們在使用MKMapView地圖控制項時,如常用的運動的APP,會在地圖上添加一些圖釘(MKAnnotation)和繪製一些線條(MKOverlay)。如果你的地圖控制項添加了圖釘以及繪製了線條,那麼正確的時機應該滿足如下三個要求:1、地圖資料載入完成;2、圖釘繪製完成;3、線條繪製完成。
那麼問題來了,如何判斷上述三種操作的已完成?經過分析,地圖資料載入和圖釘繪製沒錯,MkMapViewDelegate提供了相應的方法,分別對應的方法為:
地圖資料載入完成:
mapViewDidFinishRenderingMap:fullyRendered:
圖釘繪製完成:
mapView:didAddAnnotationViews:
線條繪製完成:
mapView:didAddOverlayRenderers:
二、地圖
地圖控制項繼承於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 *)mapViewdidDeselectAnnotationView:(MKAnnotationView *)view{ _bDrawOverlayDown = YES; [self doScreenshot];}
mapView:didAddAnnotationViews:
mapView:didAddAnnotationViews:
mapView:didAddOverlayRenderers:
mapView:didDeselectAnnotationView:
mapView:didDeselectAnnotationView:
iOS開發--MKMapView