Coder89757 Coder89757 - 1 year ago 104
iOS Question

What is the best to have URL like thumbnail indicating the location like iMessage?

I need a clickable thumbnail to indicate location, just like iMessage, what is the best way to achieve that?

enter image description here

Answer Source

You can add an MKMapView to your table cell, but the better way to go would be to use MKSnapshotter to create snapshots and adding them to your cells instead.

From NSHipster's blog post here, sample code to retrieve image from an MKMapSnapshotter is:

MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init];
options.region = self.mapView.region;
options.size = self.mapView.frame.size;
options.scale = [[UIScreen mainScreen] scale];

NSURL *fileURL = [NSURL fileURLWithPath:@"path/to/snapshot.png"];

MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];
[snapshotter startWithCompletionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
    if (error) {
        NSLog(@"[Error] %@", error);

    UIImage *image = snapshot.image;
    NSData *data = UIImagePNGRepresentation(image);
    [data writeToURL:fileURL atomically:YES];

options passed to the snapshot here are MKMapSnapshotOptions. Read the blog for more info and full tutorial.

MKMapSnapshotter is also flexible enough to add default/custom annotations to the snapshots, as you have posted in you question.

Sample code from the same source, with annotation is:

[snapshotter startWithQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
              completionHandler:^(MKMapSnapshot *snapshot, NSError *error) {
      if (error) {
          NSLog(@"[Error] %@", error);

      MKAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:nil reuseIdentifier:nil];

      UIImage *image = snapshot.image;
      UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
          [image drawAtPoint:CGPointMake(0.0f, 0.0f)];

          CGRect rect = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);
          for (id <MKAnnotation> annotation in self.mapView.annotations) {
              CGPoint point = [snapshot pointForCoordinate:annotation.coordinate];
              if (CGRectContainsPoint(rect, point)) {
                  point.x = point.x + pin.centerOffset.x -
                                (pin.bounds.size.width / 2.0f);
                  point.y = point.y + pin.centerOffset.y -
                                (pin.bounds.size.height / 2.0f);
                  [pin.image drawAtPoint:point];

          UIImage *compositeImage = UIGraphicsGetImageFromCurrentImageContext();
          NSData *data = UIImagePNGRepresentation(compositeImage);
          [data writeToURL:fileURL atomically:YES];

Tha catch here is, you will have to create an image from the snapshot with custom code.

Once the snapshot has been generated, you can plot it inside your cell.

If you want to optimize this further, you can save the generated snapshot in local storage, and use it on cell reuse for same coordinates, instead of generating an image each time the cell is reused.

Read the official documentation for MKMapSnapshotter HERE, and MKSnapshotOptions HERE.