html5中文学习网

您的位置: 首页 > ios » 正文

iOS开发:对MKMapView的性能优化_IOS开发

[ ] 已经帮助:人解决问题

   最近做的项目主要是LBS这块 主打成员定位功能 我们的UI设计是这样的2HiHTML5中文学习网 - HTML5先行者学习网

iOS开发:对MKMapView的性能优化 三联

  乍一看上去是挺好挺美观的 不同的人会显示不同的头像 可是当人扎堆的时候 问题就来了2HiHTML5中文学习网 - HTML5先行者学习网

  当人多的时候(例如上图所示) 地图滑动起来就能感觉到明显顿卡 那种不流畅感能折磨死人 所以 自然我们要解决这个问题(等等 先不要吐槽为什么不用地图聚合 因为这已经是地图放到最大了 聚合不适合这次的问题讨论)2HiHTML5中文学习网 - HTML5先行者学习网

  分析2HiHTML5中文学习网 - HTML5先行者学习网

  首先看下我是怎么实现这个annotationView的 由于这个annotationsView是异形的(也就是无法通过设置圆角直接得到) 而且里面的图片还因用户而异 所以解决方案就是使用layer.mask来进行遮罩 代码如下2HiHTML5中文学习网 - HTML5先行者学习网

  @implementation MMAnnotationView2HiHTML5中文学习网 - HTML5先行者学习网

  - (instancetype)initWithAnnotation:(id)annotation reuseIdentifier:(NSString *)reuseIdentifier2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];2HiHTML5中文学习网 - HTML5先行者学习网

  if ( self )2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  self.frame = CGRectMake(0, 0, TRACK_ANNOTATION_SIZE.width, TRACK_ANNOTATION_SIZE.height);2HiHTML5中文学习网 - HTML5先行者学习网

  self.centerOffset = CGPointMake(0, -(TRACK_ANNOTATION_SIZE.height-3)/2);2HiHTML5中文学习网 - HTML5先行者学习网

  self.canShowCallout = NO;2HiHTML5中文学习网 - HTML5先行者学习网

  self.avatarView = [[UIImageView alloc] initWithFrame:self.bounds];2HiHTML5中文学习网 - HTML5先行者学习网

  [self addSubview:self.avatarView];2HiHTML5中文学习网 - HTML5先行者学习网

  self.avatarView.contentMode = UIViewContentModeScaleAspectFill;2HiHTML5中文学习网 - HTML5先行者学习网

  CAShapeLayer *shapelayer = [CAShapeLayer layer];2HiHTML5中文学习网 - HTML5先行者学习网

  shapelayer.frame = self.bounds;2HiHTML5中文学习网 - HTML5先行者学习网

  shapelayer.path = self.framePath.CGPath;2HiHTML5中文学习网 - HTML5先行者学习网

  self.avatarView.layer.mask = shapelayer;2HiHTML5中文学习网 - HTML5先行者学习网

  self.layer.shadowPath = self.framePath.CGPath;2HiHTML5中文学习网 - HTML5先行者学习网

  self.layer.shadowRadius = 1.0f;2HiHTML5中文学习网 - HTML5先行者学习网

  self.layer.shadowColor = [UIColor colorWithHex:0x666666FF].CGColor;2HiHTML5中文学习网 - HTML5先行者学习网

  self.layer.shadowOpacity = 1.0f;2HiHTML5中文学习网 - HTML5先行者学习网

  self.layer.shadowOffset = CGSizeMake(0, 0);2HiHTML5中文学习网 - HTML5先行者学习网

  self.layer.masksToBounds = NO;2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  return self;2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  //mask路径2HiHTML5中文学习网 - HTML5先行者学习网

  - (UIBezierPath *)framePath2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  if ( !_framePath )2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  CGFloat arrowWidth = 14;2HiHTML5中文学习网 - HTML5先行者学习网

  CGMutablePathRef path = CGPathCreateMutable();2HiHTML5中文学习网 - HTML5先行者学习网

  CGRect rectangle = CGRectInset(CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetWidth(self.bounds)), 3,3);2HiHTML5中文学习网 - HTML5先行者学习网

  CGPoint p[3] = {2HiHTML5中文学习网 - HTML5先行者学习网

  {CGRectGetMidX(self.bounds)-arrowWidth/2, CGRectGetWidth(self.bounds)-6},2HiHTML5中文学习网 - HTML5先行者学习网

  {CGRectGetMidX(self.bounds)+arrowWidth/2, CGRectGetWidth(self.bounds)-6},2HiHTML5中文学习网 - HTML5先行者学习网

  {CGRectGetMidX(self.bounds), CGRectGetHeight(self.bounds)-4}2HiHTML5中文学习网 - HTML5先行者学习网

  };2HiHTML5中文学习网 - HTML5先行者学习网

  CGPathAddRoundedRect(path, NULL, rectangle, 5, 5);2HiHTML5中文学习网 - HTML5先行者学习网

  CGPathAddLines(path, NULL, p, 3);2HiHTML5中文学习网 - HTML5先行者学习网

  CGPathCloseSubpath(path);2HiHTML5中文学习网 - HTML5先行者学习网

  _framePath = [UIBezierPath bezierPathWithCGPath:path];2HiHTML5中文学习网 - HTML5先行者学习网

  CGPathRelease(path);2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  return _framePath;2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  我用代码生成了形状路径 并以此生成了layer的mask和shadowPath2HiHTML5中文学习网 - HTML5先行者学习网

  使用时 只要直接用SDWebImage设置头像就行了2HiHTML5中文学习网 - HTML5先行者学习网

  12HiHTML5中文学习网 - HTML5先行者学习网

  [annotationView.avatarView sd_setImageWithURL:[NSURL URLWithString:avatarURL] placeholderImage:placeHolderImage];2HiHTML5中文学习网 - HTML5先行者学习网

  接下来用工具分析一下问题出来哪 分析性能当然是选择Instrments(用法在这里就不做介绍了) 打开Core Animation 然后运行程序 滑动地图 可以看到性能分析如下2HiHTML5中文学习网 - HTML5先行者学习网

  原来平均帧数只有不到30帧 这离我们的目标60帧差得实在太远2HiHTML5中文学习网 - HTML5先行者学习网

  再使用Debug Option来深入分析一下2HiHTML5中文学习网 - HTML5先行者学习网

  由于MKMapView的原因 这里我们主要关心这几个选项2HiHTML5中文学习网 - HTML5先行者学习网

  Color Blended Layers2HiHTML5中文学习网 - HTML5先行者学习网

  Color Misaligned Images2HiHTML5中文学习网 - HTML5先行者学习网

  Color Offscreen-Rendered Yellow2HiHTML5中文学习网 - HTML5先行者学习网

  分别打开这几个选项 结果如下2HiHTML5中文学习网 - HTML5先行者学习网

  可以看到2HiHTML5中文学习网 - HTML5先行者学习网

  Color Blended Layers没有问题 不过这也是正常的 由于使用了mask 没有透明的地方2HiHTML5中文学习网 - HTML5先行者学习网

  Color Misaligned Images除了默认头像外全中 这是因为服务器上的图片大小跟显示的大小不一致 导致缩放 而默认头像则是一致的 所以没问题2HiHTML5中文学习网 - HTML5先行者学习网

  Color Offscreen-Rendered Yellow全中 由于使用了mask 导致大量的离屏渲染 这也是性能下降的主要原因2HiHTML5中文学习网 - HTML5先行者学习网

  解决2HiHTML5中文学习网 - HTML5先行者学习网

  问题的原因找到了 那么接下来该如何解决呢?2HiHTML5中文学习网 - HTML5先行者学习网

  首先mask是肯定不能用了2HiHTML5中文学习网 - HTML5先行者学习网

  其次下载下来的图片我们要预处理成实际大小2HiHTML5中文学习网 - HTML5先行者学习网

  那么 直接把下载下来的图片合成为我们要显示的最终结果不就ok了吗? 试试看2HiHTML5中文学习网 - HTML5先行者学习网

  - (void)loadAnnotationImageWithURL:(NSString*)url imageView:(UIImageView*)imageView2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  //将合成后的图片缓存起来2HiHTML5中文学习网 - HTML5先行者学习网

  NSString *annoImageURL = url;2HiHTML5中文学习网 - HTML5先行者学习网

  NSString *annoImageCacheURL = [annoImageURL stringByAppendingString:@"cache"];2HiHTML5中文学习网 - HTML5先行者学习网

  UIImage *cacheImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:annoImageCacheURL];2HiHTML5中文学习网 - HTML5先行者学习网

  if ( cacheImage )2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  //LLLog(@"hit cache");2HiHTML5中文学习网 - HTML5先行者学习网

  imageView.image = cacheImage;2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  else2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  //LLLog(@"no cache");2HiHTML5中文学习网 - HTML5先行者学习网

  [imageView sd_setImageWithURL:[NSURL URLWithString:annoImageURL]2HiHTML5中文学习网 - HTML5先行者学习网

  placeholderImage:placeHolderImage2HiHTML5中文学习网 - HTML5先行者学习网

  completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {2HiHTML5中文学习网 - HTML5先行者学习网

  if (!error)2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  UIImage *annoImage = [image annotationImage];2HiHTML5中文学习网 - HTML5先行者学习网

  imageView.image = annoImage;2HiHTML5中文学习网 - HTML5先行者学习网

  [[SDImageCache sharedImageCache] storeImage:annoImage forKey:annoImageCacheURL];2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  }];2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  @implementation UIImage (LJC)2HiHTML5中文学习网 - HTML5先行者学习网

  - (UIImage*) annotationImage2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  static UIView *snapshotView = nil;2HiHTML5中文学习网 - HTML5先行者学习网

  static UIImageView *imageView = nil;2HiHTML5中文学习网 - HTML5先行者学习网

  if ( !snapshotView )2HiHTML5中文学习网 - HTML5先行者学习网

  {2HiHTML5中文学习网 - HTML5先行者学习网

  snapshotView = [UIView new];2HiHTML5中文学习网 - HTML5先行者学习网

  snapshotView.frame = CGRectMake(0, 0, TRACK_ANNOTATION_SIZE.width, TRACK_ANNOTATION_SIZE.height);2HiHTML5中文学习网 - HTML5先行者学习网

  imageView = [UIImageView new];2HiHTML5中文学习网 - HTML5先行者学习网

  [snapshotView addSubview:imageView];2HiHTML5中文学习网 - HTML5先行者学习网

  imageView.clipsToBounds = YES;2HiHTML5中文学习网 - HTML5先行者学习网

  imageView.frame = snapshotView.bounds;2HiHTML5中文学习网 - HTML5先行者学习网

  imageView.contentMode = UIViewContentModeScaleAspectFill;2HiHTML5中文学习网 - HTML5先行者学习网

  CGFloat arrowWidth = 14;2HiHTML5中文学习网 - HTML5先行者学习网

  CGMutablePathRef path = CGPathCreateMutable();2HiHTML5中文学习网 - HTML5先行者学习网

  CGRect rectangle = CGRectInset(CGRectMake(0, 0, CGRectGetWidth(imageView.bounds), CGRectGetWidth(imageView.bounds)), 3,3);2HiHTML5中文学习网 - HTML5先行者学习网

  CGPoint p[3] = {2HiHTML5中文学习网 - HTML5先行者学习网

  {CGRectGetMidX(imageView.bounds)-arrowWidth/2, CGRectGetWidth(imageView.bounds)-6},2HiHTML5中文学习网 - HTML5先行者学习网

  {CGRectGetMidX(imageView.bounds)+arrowWidth/2, CGRectGetWidth(imageView.bounds)-6},2HiHTML5中文学习网 - HTML5先行者学习网

  {CGRectGetMidX(imageView.bounds), CGRectGetHeight(imageView.bounds)-4}2HiHTML5中文学习网 - HTML5先行者学习网

  };2HiHTML5中文学习网 - HTML5先行者学习网

  CGPathAddRoundedRect(path, NULL, rectangle, 5, 5);2HiHTML5中文学习网 - HTML5先行者学习网

  CGPathAddLines(path, NULL, p, 3);2HiHTML5中文学习网 - HTML5先行者学习网

  CGPathCloseSubpath(path);2HiHTML5中文学习网 - HTML5先行者学习网

  CAShapeLayer *shapelayer = [CAShapeLayer layer];2HiHTML5中文学习网 - HTML5先行者学习网

  shapelayer.frame = imageView.bounds;2HiHTML5中文学习网 - HTML5先行者学习网

  shapelayer.path = path;2HiHTML5中文学习网 - HTML5先行者学习网

  imageView.layer.mask = shapelayer;2HiHTML5中文学习网 - HTML5先行者学习网

  snapshotView.layer.shadowPath = path;2HiHTML5中文学习网 - HTML5先行者学习网

  snapshotView.layer.shadowRadius = 1.0f;2HiHTML5中文学习网 - HTML5先行者学习网

  snapshotView.layer.shadowColor = [UIColor colorWithHex:0x666666FF].CGColor;2HiHTML5中文学习网 - HTML5先行者学习网

  snapshotView.layer.shadowOpacity = 1.0f;2HiHTML5中文学习网 - HTML5先行者学习网

  snapshotView.layer.shadowOffset = CGSizeMake(0, 0);2HiHTML5中文学习网 - HTML5先行者学习网

  CGPathRelease(path);2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  imageView.image = self;2HiHTML5中文学习网 - HTML5先行者学习网

  UIGraphicsBeginImageContextWithOptions(TRACK_ANNOTATION_SIZE, NO, 0);2HiHTML5中文学习网 - HTML5先行者学习网

  [snapshotView.layer renderInContext:UIGraphicsGetCurrentContext()];2HiHTML5中文学习网 - HTML5先行者学习网

  UIImage *copied = UIGraphicsGetImageFromCurrentImageContext();2HiHTML5中文学习网 - HTML5先行者学习网

  UIGraphicsEndImageContext();2HiHTML5中文学习网 - HTML5先行者学习网

  return copied;2HiHTML5中文学习网 - HTML5先行者学习网

  }2HiHTML5中文学习网 - HTML5先行者学习网

  @end2HiHTML5中文学习网 - HTML5先行者学习网

  然后使用的时候 只要简单的如下调用就OK了2HiHTML5中文学习网 - HTML5先行者学习网

  [self loadAnnotationImageWithURL:avatarURL imageView:annotationView.avatarView];2HiHTML5中文学习网 - HTML5先行者学习网

  看看修改之后的Instruments表现如何2HiHTML5中文学习网 - HTML5先行者学习网

  Color Blended Layers全中 这也是无可避免的 因为显示的就是一张带透明度的图 但是由于地图的特殊性(头像的位置变化间隔较长 所以不会经常引发合成 也没有动画) 所以这里也不是问题2HiHTML5中文学习网 - HTML5先行者学习网

  Color Misaligned Images没问题了 因为头像已被缩放成了相同大小2HiHTML5中文学习网 - HTML5先行者学习网

  Color Offscreen-Rendered Yellow没问题了 因为只是简单的显示了一张图片 而并没有需要离屏渲染的东西了2HiHTML5中文学习网 - HTML5先行者学习网

  再来看下帧数情况2HiHTML5中文学习网 - HTML5先行者学习网

  Oh-Yeah~ 不光帧数达到了我们的目标60帧(由于还有业务逻辑线程在后台跑 所以没有那么的稳定) 就连平均运行耗时都下降了不少 就算地图上再多显示几十个人 也不成问题了2HiHTML5中文学习网 - HTML5先行者学习网

  小结2HiHTML5中文学习网 - HTML5先行者学习网

  不光是MKMapView 其实包括UITableView在内的很多地方都可以用文中所说的方法去优化 其核心点就是 合成+缓存 当然 由于合成还是会耗费一部分资源的 所以比较适合头像这种小的资源2HiHTML5中文学习网 - HTML5先行者学习网

  关于图形性能优化 可以看下这篇好文(有对文中提到的Debug Option不太明白的 这里有详细的解释)2HiHTML5中文学习网 - HTML5先行者学习网

(责任编辑:)
推荐书籍
推荐资讯
关于HTML5先行者 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助