SlideShare a Scribd company logo
1 of 44
Download to read offline
Maps on the
                                  iPhone
                                Using MapKit for Fun and Profit




Wednesday, September 30, 2009                                     1
Add A MKMapView




Wednesday, September 30, 2009                     2
Tweak Parameters


                                Show the blue breathing dot




                                            Then Build and Go...


Wednesday, September 30, 2009                                      3
And Bada-Boom
                                  A Map App




Wednesday, September 30, 2009                   4
But we want more,
                                like the breathing
                                     Blue Dot




Wednesday, September 30, 2009                        5
Where we are
                                       Headed
                                ‘Right’ Action - Details



                                ‘Left’ Action - Shake Map



                                Animated ‘Breathing’




Wednesday, September 30, 2009                              6
Stuff To Do
                  • View Based Project
                  • Parse XML from USGS
                  • Create Earthquakes
                  • Store Earthquakes
                  • Add Annotations
                  • Provide Annotation Views
                  • Respond to Events

Wednesday, September 30, 2009                  7
View Based Project
              Connect the
            MapView to our VC
Wednesday, September 30, 2009                   8
Parse XML
              NSOperationQueue


             operation
                                NSOperation
              thread




                                                        parseForData:




                                addOperation:




                                                                                                                                         Parse XML
                                                                 EarthquakeParser


                         initWithContentsOfURL:

                                 parse
                                                                              invokeOnMainThread:
                                                       didStartElement:
                                                  foundCharcters:
                                           didEndElement:
                NSXMLParser
                                                                          event
                                                                          loop




                                                            addEarthquake:
                                                            parserFinished




                                                                     EarthquakeParserDelegate
                                                                    (MapQuakesViewController)




                                                                                                    Don’t block the main event thread!


Wednesday, September 30, 2009                                                                                                                    9
NSOperationQueue


                operation
                                  NSOperation
                 thread




                                                                                                       Parse XML
                                                parseForData:




                                addOperation:      EarthquakeParser




         Kick Off The Parse                                     parseForData: is on an alternate thread,
                                                                won’t block event thread while
                                                                downloading the XML



Wednesday, September 30, 2009                                                                                 10
EarthquakeParser


                           initWithContentsOfURL:




                                                                                                        Parse XML
                                   parse




                   NSXMLParser




         Parse XML on the                                        Each XML Event comes to the parser’s
                                                                 delegate on the alternate thread
         alternate thread
Wednesday, September 30, 2009                                                                                 11
NSXMLParser Kick-off
  - (BOOL)parseForData {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    NSURL *url = [NSURL URLWithString:feedURLString];




                                                                               Parse XML
    BOOL success = NO;
    NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    [parser setDelegate:self];
    [parser setShouldProcessNamespaces:NO];
    [parser setShouldReportNamespacePrefixes:NO];
    [parser setShouldResolveExternalEntities:NO];
    success = [parser parse];
    NSError *parseError = [parser parserError];
    if (parseError) {
  ! NSLog(@"parse error = %@", parseError);
    }
    [parser release];
    [pool drain];
    return success;
  }




Wednesday, September 30, 2009                                                        12
Create Earthquakes
                                                    EarthquakeParser




                                          didStartElement:
                                     foundCharcters:
                                didEndElement:
                NSXMLParser




         Parse XML on the                                       Each XML Event comes to the parser’s
                                                                delegate on the alternate thread
         alternate thread
Wednesday, September 30, 2009                                                                                       13
Entry Element starts
                          and Earthquake
 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
   namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName




                                                                                    Create Earthquakes
     attributes:(NSDictionary *)attributeDict {
   if(nil != qName) {
     elementName = qName; // swap for the qName if we have a name space
   }

     if ([elementName isEqualToString:@"entry"]) {
       self.currentEarthquake = [[[Earthquake alloc] init] autorelease];
     } else if([elementName isEqualToString:@"link"]) {
       // ignore the related content and just grab the alternate
       if ([[attributeDict valueForKey:@"rel"] isEqualToString:@"alternate"]) {
         NSString *link = [attributeDict valueForKey:@"href"];
         self.currentEarthquake.detailsURL =
              [NSString stringWithFormat:@"http://earthquake.usgs.gov/%@", link];
       }
     } else if([elementName isEqualToString:@"title"] ||
                [elementName isEqualToString:@"updated"] ||
                [elementName isEqualToString:@"id"] ||
                [elementName isEqualToString:@"georss:point"] ||
                [elementName isEqualToString:@"georss:elev"]) {
       self.propertyValue = [NSMutableString string];
     } else {
       self.propertyValue = nil;
     }
 }


Wednesday, September 30, 2009                                                                    14
EarthquakeParser                     Back to the Main
                                                                         Thread




                                                                                                          Store Earthquakes
                                           invokeOnMainThread:




                                       event
                                       loop




                      addEarthquake:




                                  EarthquakeParserDelegate
                                                                 Let the main thread know an earthquake was
                                 (MapQuakesViewController)
                                                                 found by pushing the addEarthquake: and
                                                                 parserFinished methods onto the main thread




Wednesday, September 30, 2009                                                                                          15
Ending Element Pushes
                       Earthquake




                                                                                   Store Earthquakes
  - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
    namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
  ...
    } else if([elementName isEqualToString:@"entry"]) {
      Earthquake *quake = self.currentEarthquake;
      self.currentEarthquake = nil;
      [(id)[self delegate] performSelectorOnMainThread:@selector(addEarthquake:)
                                            withObject:quake
                                         waitUntilDone:NO];
    }
  }




Wednesday, September 30, 2009                                                                  16
MapQuakesVC holds the
                     Earthquakes




                                                         Store Earthquakes
      - (void)addEarthquake:(Earthquake *)earthquake {
        [self.earthquakes addObject:earthquake];
      }




Wednesday, September 30, 2009                                         17
EarthquakeParser                        Back to the Main
                                                                       Thread




                                                                                                         Add Annotations
                                         invokeOnMainThread:




                                     event
                                     loop




                   parserFinished




                                 EarthquakeParserDelegate      Once all the XML is parsed we tell the delegate
                                (MapQuakesViewController)      which displays the earthquakes in the form of an
                                                               annotation.




Wednesday, September 30, 2009                                                                                       18
Back to the Main Thread
                          Again




                                                                                 Add Annotations
  - (void)parserDidEndDocument:(NSXMLParser *)parser {
    [(id)[self delegate] performSelectorOnMainThread:@selector(parserFinished)
                                          withObject:nil
                                       waitUntilDone:NO];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    [self autorelease];
  }




Wednesday, September 30, 2009                                                               19
Display Earthquakes as
                        Annotations




                                            Add Annotations
       - (void)parserFinished {
         [self displayEarthquakes];
       }




Wednesday, September 30, 2009                          20
Remove Old Annotations
- (void)displayEarthquakes {




                                                                    Add Annotations
  [self removeAnnotations];
  NSArray *visibleQuakes = [self sortAndFilterEarthquakes];
  // limit the numer to 100
  if(visibleQuakes.count > 100) {
    // remove the earthquakes from the top of the
    // list until we are down to 100
    NSUInteger removeCount = visibleQuakes.count - 100;
    NSRange keepers = {removeCount, 100}; // location and length
    visibleQuakes = [visibleQuakes subarrayWithRange:keepers];
  }

    for(Earthquake *earthquake in visibleQuakes) {
      EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation
                                   annotationWithEarthquake:earthquake];
      [self.mapView addAnnotation:eqAnn];
    }
}


Wednesday, September 30, 2009                                                  21
Find Visible Quakes
                          Sorted by Magnitude
- (void)displayEarthquakes {




                                                                    Add Annotations
  [self removeAnnotations];
  NSArray *visibleQuakes = [self sortAndFilterEarthquakes];
  // limit the numer to 100
  if(visibleQuakes.count > 100) {
    // remove the earthquakes from the top of the
    // list until we are down to 100
    NSUInteger removeCount = visibleQuakes.count - 100;
    NSRange keepers = {removeCount, 100}; // location and length
    visibleQuakes = [visibleQuakes subarrayWithRange:keepers];
  }

    for(Earthquake *earthquake in visibleQuakes) {
      EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation
                                   annotationWithEarthquake:earthquake];
      [self.mapView addAnnotation:eqAnn];
    }
}


Wednesday, September 30, 2009                                                  22
Limit Earthquakes to
                                  100
- (void)displayEarthquakes {




                                                                    Add Annotations
  [self removeAnnotations];
  NSArray *visibleQuakes = [self sortAndFilterEarthquakes];
  // limit the numer to 100
  if(visibleQuakes.count > 100) {
    // remove the earthquakes from the top of the
    // list until we are down to 100
    NSUInteger removeCount = visibleQuakes.count - 100;
    NSRange keepers = {removeCount, 100}; // location and length
    visibleQuakes = [visibleQuakes subarrayWithRange:keepers];
  }

    for(Earthquake *earthquake in visibleQuakes) {
      EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation
                                   annotationWithEarthquake:earthquake];
      [self.mapView addAnnotation:eqAnn];
    }
}


Wednesday, September 30, 2009                                                  23
Find and Display
                                  Earthquakes
- (void)displayEarthquakes {




                                                                    Add Annotations
  [self removeAnnotations];
  NSArray *visibleQuakes = [self sortAndFilterEarthquakes];
  // limit the numer to 100
  if(visibleQuakes.count > 100) {
    // remove the earthquakes from the top of the
    // list until we are down to 100
    NSUInteger removeCount = visibleQuakes.count - 100;
    NSRange keepers = {removeCount, 100}; // location and length
    visibleQuakes = [visibleQuakes subarrayWithRange:keepers];
  }

    for(Earthquake *earthquake in visibleQuakes) {
      EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation
                                   annotationWithEarthquake:earthquake];
      [self.mapView addAnnotation:eqAnn];
    }
}


Wednesday, September 30, 2009                                                  24
Remove old Earthquake
                       Annotations




                                                                                 Add Annotations
 - (void) removeAnnotations {
   // remove the old annotations but
   // don't modify the array while iterating
   NSArray *annotationsCopy = [self.mapView.annotations copy];
   for(id annotation in annotationsCopy) {
     if([[annotation class] isSubclassOfClass:[EarthquakeAnnotation class]]) {
       [self.mapView removeAnnotation:annotation];
     }
   }
   [annotationsCopy release];
 }




Wednesday, September 30, 2009                                                               25
Filter Visible
                                Earthquakes
  - (NSArray *)sortAndFilterEarthquakes {




                                                                                      Add Annotations
    // find the visible earthquakes
    MKCoordinateRegion region = [self.mapView region];
    LocationBoundingBox bbox = LocationBoundingBoxMake(region.center, region.span);
    NSPredicate *latPred = [NSPredicate predicateWithFormat:
                            @"latitude BETWEEN {%@, %@}",
                            [NSNumber numberWithFloat:bbox.min.latitude],
                            [NSNumber numberWithFloat:bbox.max.latitude]];
    NSPredicate *lonPred = [NSPredicate predicateWithFormat:
                            @"longitude BETWEEN {%@, %@}",
                            [NSNumber numberWithFloat:bbox.min.longitude],
                            [NSNumber numberWithFloat:bbox.max.longitude]];
    NSArray *predicates = [NSArray arrayWithObjects:latPred, lonPred, nil];
    NSPredicate *locationPred = [NSCompoundPredicate
                                 andPredicateWithSubpredicates:predicates];
    NSArray *quakes = [self.earthquakes
                       filteredArrayUsingPredicate:locationPred];
    NSSortDescriptor *descriptor = [[NSSortDescriptor alloc]
                                    initWithKey:@"magnitude"
                                    ascending:YES];
    NSArray *descriptors = [NSArray arrayWithObject:descriptor];
    NSArray *sortedEarthquakes = [quakes sortedArrayUsingDescriptors:descriptors];
    [descriptor release];
    return sortedEarthquakes;
  }

Wednesday, September 30, 2009                                                                    26
Sort Earthquakes
  - (NSArray *)sortAndFilterEarthquakes {




                                                                                      Add Annotations
    // find the visible earthquakes
    MKCoordinateRegion region = [self.mapView region];
    LocationBoundingBox bbox = LocationBoundingBoxMake(region.center, region.span);
    NSPredicate *latPred = [NSPredicate predicateWithFormat:
                            @"latitude BETWEEN {%@, %@}",
                            [NSNumber numberWithFloat:bbox.min.latitude],
                            [NSNumber numberWithFloat:bbox.max.latitude]];
    NSPredicate *lonPred = [NSPredicate predicateWithFormat:
                            @"longitude BETWEEN {%@, %@}",
                            [NSNumber numberWithFloat:bbox.min.longitude],
                            [NSNumber numberWithFloat:bbox.max.longitude]];
    NSArray *predicates = [NSArray arrayWithObjects:latPred, lonPred, nil];
    NSPredicate *locationPred = [NSCompoundPredicate
                                 andPredicateWithSubpredicates:predicates];
    NSArray *quakes = [self.earthquakes
                       filteredArrayUsingPredicate:locationPred];
    NSSortDescriptor *descriptor = [[NSSortDescriptor alloc]
                                    initWithKey:@"magnitude"
                                    ascending:YES];
    NSArray *descriptors = [NSArray arrayWithObject:descriptor];
    NSArray *sortedEarthquakes = [quakes sortedArrayUsingDescriptors:descriptors];
    [descriptor release];
    return sortedEarthquakes;
  }

Wednesday, September 30, 2009                                                                    27
Provide Annotation Views
                                       EarthquakeParserDelegate
                                      (MapQuakesViewController)




                                   addAnnotation:




                                viewForAnnotation:




                                     MKMapViewDelegate
                                  (MapQuakesViewController)




         delegate Provides
         Annotation View
Wednesday, September 30, 2009                                                       28
Return nil for user




                                                                                  Provide Annotation Views
                                location
 - (MKAnnotationView *)mapView:(MKMapView *)mapView
              viewForAnnotation:(id <MKAnnotation>)annotation {
   MKAnnotationView *view = nil;
   if(annotation != mapView.userLocation) {
 !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation;
 !! view = [self.mapView
              dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"];
 !! if(nil == view) {
        view = [[[EarthquakeAnnotationView alloc]
                 initWithAnnotation:eqAnn
                 reuseIdentifier:@"earthquakeLoc"] autorelease];
 !! }
     view.annotation = annotation;
     [view setCanShowCallout:YES];
     UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
     [view setRightCalloutAccessoryView:button];
   }
   return view;
 }




Wednesday, September 30, 2009                                                                       29
Provide Annotation Views
                 Reuse Annotation Views
 - (MKAnnotationView *)mapView:(MKMapView *)mapView
              viewForAnnotation:(id <MKAnnotation>)annotation {
   MKAnnotationView *view = nil;
   if(annotation != mapView.userLocation) {
 !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation;
 !! view = [self.mapView
              dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"];
 !! if(nil == view) {
        view = [[[EarthquakeAnnotationView alloc]
                 initWithAnnotation:eqAnn
                 reuseIdentifier:@"earthquakeLoc"] autorelease];
 !! }
     view.annotation = annotation;
     [view setCanShowCallout:YES];
     UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
     [view setRightCalloutAccessoryView:button];
   }
   return view;
 }




Wednesday, September 30, 2009                                                                       30
Create if no re-useable




                                                                                  Provide Annotation Views
                        views exist
 - (MKAnnotationView *)mapView:(MKMapView *)mapView
              viewForAnnotation:(id <MKAnnotation>)annotation {
   MKAnnotationView *view = nil;
   if(annotation != mapView.userLocation) {
 !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation;
 !! view = [self.mapView
              dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"];
 !! if(nil == view) {
        view = [[[EarthquakeAnnotationView alloc]
                 initWithAnnotation:eqAnn
                 reuseIdentifier:@"earthquakeLoc"] autorelease];
 !! }
     view.annotation = annotation;
     [view setCanShowCallout:YES];
     UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
     [view setRightCalloutAccessoryView:button];
   }
   return view;
 }




Wednesday, September 30, 2009                                                                       31
Provide Annotation Views
                                Congure View
 - (MKAnnotationView *)mapView:(MKMapView *)mapView
              viewForAnnotation:(id <MKAnnotation>)annotation {
   MKAnnotationView *view = nil;
   if(annotation != mapView.userLocation) {
 !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation;
 !! view = [self.mapView
              dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"];
 !! if(nil == view) {
        view = [[[EarthquakeAnnotationView alloc]
                 initWithAnnotation:eqAnn
                 reuseIdentifier:@"earthquakeLoc"] autorelease];
 !! }
    view.annotation = annotation;
    [view setCanShowCallout:YES];
    UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
     [view setRightCalloutAccessoryView:button];
   }
   return view;
 }




Wednesday, September 30, 2009                                                                      32
Custom




                                                     Provide Annotation Views
                                   MKAnnotationView
                                   Subclass




                                EarthquakeAnnotationView


Wednesday, September 30, 2009                                          33
Congure the




                                                                         Provide Annotation Views
                                Annotation View

- (void)setAnnotation:annotation {
  [super setAnnotation:annotation];

    [self.layer.sublayers makeObjectsPerformSelector:
                                @selector(removeFromSuperlayer)];

    self.frame = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f);

    self.earthquake = [(EarthquakeAnnotation *)annotation earthquake];
    [self addBreathingLayer];
    [self addDarkCircleLayer];

}




Wednesday, September 30, 2009                                                              34
Provide Annotation Views
                                Shape Layer
  - (void) addBreathingLayer {
    self.circleLayer = [CAShapeLayer layer];
    CGColorRef color = [self newFillColor];
    self.circleLayer.fillColor = color;
    CGColorRelease(color);
    color = [self newStrokeColor];
    self.circleLayer.strokeColor = color;
    CGColorRelease(color);
    self.circleLayer.lineWidth = 1.0f;
    CGMutablePathRef path = CGPathCreateMutable();
    CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f);
    CGPathAddEllipseInRect(path, NULL, square);
    self.circleLayer.path = path;
    CGPathRelease(path);
    self.circleLayer.frame = square;
    CABasicAnimation *pathAnimation =
        [CABasicAnimation animationWithKeyPath:@"path"];
    pathAnimation.duration = 1.5f;
    pathAnimation.timingFunction =
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    pathAnimation.repeatCount = 1E100f;
    pathAnimation.autoreverses = YES;
    self.circleLayer.actions = [NSDictionary dictionaryWithObject:pathAnimation
                                                           forKey:@"path"];
    [self.layer addSublayer:self.circleLayer];
  }


Wednesday, September 30, 2009                                                                             35
Provide Annotation Views
                          Breathing Animation
  - (void) addBreathingLayer {
    self.circleLayer = [CAShapeLayer layer];
    CGColorRef color = [self newFillColor];
    self.circleLayer.fillColor = color;
    CGColorRelease(color);
    color = [self newStrokeColor];
    self.circleLayer.strokeColor = color;
    CGColorRelease(color);
    self.circleLayer.lineWidth = 1.0f;
    CGMutablePathRef path = CGPathCreateMutable();
    CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f);
    CGPathAddEllipseInRect(path, NULL, square);
    self.circleLayer.path = path;
    CGPathRelease(path);
    self.circleLayer.frame = square;
    CABasicAnimation *pathAnimation =
        [CABasicAnimation animationWithKeyPath:@"path"];
    pathAnimation.duration = 1.5f;
    pathAnimation.timingFunction =
        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    pathAnimation.repeatCount = 1E100f;
    pathAnimation.autoreverses = YES;
    self.circleLayer.actions = [NSDictionary dictionaryWithObject:pathAnimation
                                                           forKey:@"path"];
    [self.layer addSublayer:self.circleLayer];
  }


Wednesday, September 30, 2009                                                                             36
Selection Starts




                                                                         Provide Annotation Views
                                   Animation
   - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
     [super setSelected:selected animated:animated];
     if(YES == selected) {
       // animate the bottom shape's path
       CGRect square = CGRectMake(16.0f, 16.0f, 16.0f, 16.0f);
       CGMutablePathRef path = CGPathCreateMutable();
       CGPathAddEllipseInRect(path, NULL, square);
       self.circleLayer.path = path;
       CGPathRelease(path);
       EarthquakeParser *parser = [EarthquakeParser earthquakeParser];
       parser.delegate = self;
       [parser getShakeMapForEarthquake:self.earthquake];
     } else {
       [CATransaction begin];
       [CATransaction setDisableActions:YES];
       CGMutablePathRef path = CGPathCreateMutable();
       CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f);
       CGPathAddEllipseInRect(path, NULL, square);
       self.circleLayer.path = path;
       CGPathRelease(path);
       [CATransaction commit];
     }
   }




Wednesday, September 30, 2009                                                              37
De-Selection Stops




                                                                         Provide Annotation Views
                                    Animation
   - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
     [super setSelected:selected animated:animated];
     if(YES == selected) {
       // animate the bottom shape's path
       CGRect square = CGRectMake(16.0f, 16.0f, 16.0f, 16.0f);
       CGMutablePathRef path = CGPathCreateMutable();
       CGPathAddEllipseInRect(path, NULL, square);
       self.circleLayer.path = path;
       CGPathRelease(path);
       EarthquakeParser *parser = [EarthquakeParser earthquakeParser];
       parser.delegate = self;
       [parser getShakeMapForEarthquake:self.earthquake];
     } else {
       [CATransaction begin];
       [CATransaction setDisableActions:YES];
       CGMutablePathRef path = CGPathCreateMutable();
       CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f);
       CGPathAddEllipseInRect(path, NULL, square);
       self.circleLayer.path = path;
       CGPathRelease(path);
       [CATransaction commit];
     }
   }




Wednesday, September 30, 2009                                                              38
Selected Animation




                                                Provide Annotation Views
Wednesday, September 30, 2009                                     39
‘Right’ Detail




                                                   Respond To Events
                                ‘Left’ Shake Map




Wednesday, September 30, 2009                                   40
Open The Web Page




                                                                                        Respond To Events
 - (void)mapView:(MKMapView *)mapView
   annotationView:(MKAnnotationView *)view
 calloutAccessoryControlTapped:(UIControl *)control {
    NSURL *url = nil;
    EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation *)[view annotation];
    if(view.rightCalloutAccessoryView == control) {
      NSString *urlString = [eqAnn.earthquake.detailsURL
                         stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
       url = [NSURL URLWithString:urlString];
    } else {
      NSString *urlString = [eqAnn.earthquake.shakeMapURL
                         stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
       url = [NSURL URLWithString:urlString];
    }
    [[UIApplication sharedApplication] openURL:url];
 }




Wednesday, September 30, 2009                                                                        41
Where To Now?
                   • Your data will likely have more
                     interesting selection criteria, exploit it
                   • The ‘detail’ from right and left buttons
                     can do lots more interesting stuff
                         • USGS Provides KML files for shake
                           maps
                   • Use Core Animation in the right or left
                     buttons

Wednesday, September 30, 2009                                     42
Summary


                   • Filtering your Annotations is important
                     if you have lots of data
                   • It’s easy to build your own custom
                     annotation views and add Core
                     Animation to them



Wednesday, September 30, 2009                                  43
Thanks!
                                Pragmatic iPhone Studio




Wednesday, September 30, 2009                             44

More Related Content

Recently uploaded

Enzyme, Pharmaceutical Aids, Miscellaneous Last Part of Chapter no 5th.pdf
Enzyme, Pharmaceutical Aids, Miscellaneous Last Part of Chapter no 5th.pdfEnzyme, Pharmaceutical Aids, Miscellaneous Last Part of Chapter no 5th.pdf
Enzyme, Pharmaceutical Aids, Miscellaneous Last Part of Chapter no 5th.pdfSumit Tiwari
 
Separation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesSeparation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesFatimaKhan178732
 
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions  for the students and aspirants of Chemistry12th.pptxOrganic Name Reactions  for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions for the students and aspirants of Chemistry12th.pptxVS Mahajan Coaching Centre
 
Introduction to ArtificiaI Intelligence in Higher Education
Introduction to ArtificiaI Intelligence in Higher EducationIntroduction to ArtificiaI Intelligence in Higher Education
Introduction to ArtificiaI Intelligence in Higher Educationpboyjonauth
 
How to Configure Email Server in Odoo 17
How to Configure Email Server in Odoo 17How to Configure Email Server in Odoo 17
How to Configure Email Server in Odoo 17Celine George
 
Presiding Officer Training module 2024 lok sabha elections
Presiding Officer Training module 2024 lok sabha electionsPresiding Officer Training module 2024 lok sabha elections
Presiding Officer Training module 2024 lok sabha electionsanshu789521
 
mini mental status format.docx
mini    mental       status     format.docxmini    mental       status     format.docx
mini mental status format.docxPoojaSen20
 
A Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformA Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformChameera Dedduwage
 
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptxSOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptxiammrhaywood
 
How to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxHow to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxmanuelaromero2013
 
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Krashi Coaching
 
_Math 4-Q4 Week 5.pptx Steps in Collecting Data
_Math 4-Q4 Week 5.pptx Steps in Collecting Data_Math 4-Q4 Week 5.pptx Steps in Collecting Data
_Math 4-Q4 Week 5.pptx Steps in Collecting DataJhengPantaleon
 
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17Celine George
 
The basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxThe basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxheathfieldcps1
 
Employee wellbeing at the workplace.pptx
Employee wellbeing at the workplace.pptxEmployee wellbeing at the workplace.pptx
Employee wellbeing at the workplace.pptxNirmalaLoungPoorunde1
 
Call Girls in Dwarka Mor Delhi Contact Us 9654467111
Call Girls in Dwarka Mor Delhi Contact Us 9654467111Call Girls in Dwarka Mor Delhi Contact Us 9654467111
Call Girls in Dwarka Mor Delhi Contact Us 9654467111Sapana Sha
 
The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13Steve Thomason
 

Recently uploaded (20)

Enzyme, Pharmaceutical Aids, Miscellaneous Last Part of Chapter no 5th.pdf
Enzyme, Pharmaceutical Aids, Miscellaneous Last Part of Chapter no 5th.pdfEnzyme, Pharmaceutical Aids, Miscellaneous Last Part of Chapter no 5th.pdf
Enzyme, Pharmaceutical Aids, Miscellaneous Last Part of Chapter no 5th.pdf
 
TataKelola dan KamSiber Kecerdasan Buatan v022.pdf
TataKelola dan KamSiber Kecerdasan Buatan v022.pdfTataKelola dan KamSiber Kecerdasan Buatan v022.pdf
TataKelola dan KamSiber Kecerdasan Buatan v022.pdf
 
Separation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesSeparation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and Actinides
 
9953330565 Low Rate Call Girls In Rohini Delhi NCR
9953330565 Low Rate Call Girls In Rohini  Delhi NCR9953330565 Low Rate Call Girls In Rohini  Delhi NCR
9953330565 Low Rate Call Girls In Rohini Delhi NCR
 
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions  for the students and aspirants of Chemistry12th.pptxOrganic Name Reactions  for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
 
Introduction to ArtificiaI Intelligence in Higher Education
Introduction to ArtificiaI Intelligence in Higher EducationIntroduction to ArtificiaI Intelligence in Higher Education
Introduction to ArtificiaI Intelligence in Higher Education
 
How to Configure Email Server in Odoo 17
How to Configure Email Server in Odoo 17How to Configure Email Server in Odoo 17
How to Configure Email Server in Odoo 17
 
Presiding Officer Training module 2024 lok sabha elections
Presiding Officer Training module 2024 lok sabha electionsPresiding Officer Training module 2024 lok sabha elections
Presiding Officer Training module 2024 lok sabha elections
 
mini mental status format.docx
mini    mental       status     format.docxmini    mental       status     format.docx
mini mental status format.docx
 
A Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy ReformA Critique of the Proposed National Education Policy Reform
A Critique of the Proposed National Education Policy Reform
 
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptxSOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
 
How to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxHow to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptx
 
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
Kisan Call Centre - To harness potential of ICT in Agriculture by answer farm...
 
_Math 4-Q4 Week 5.pptx Steps in Collecting Data
_Math 4-Q4 Week 5.pptx Steps in Collecting Data_Math 4-Q4 Week 5.pptx Steps in Collecting Data
_Math 4-Q4 Week 5.pptx Steps in Collecting Data
 
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
Incoming and Outgoing Shipments in 1 STEP Using Odoo 17
 
The basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxThe basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptx
 
Employee wellbeing at the workplace.pptx
Employee wellbeing at the workplace.pptxEmployee wellbeing at the workplace.pptx
Employee wellbeing at the workplace.pptx
 
Model Call Girl in Bikash Puri Delhi reach out to us at 🔝9953056974🔝
Model Call Girl in Bikash Puri  Delhi reach out to us at 🔝9953056974🔝Model Call Girl in Bikash Puri  Delhi reach out to us at 🔝9953056974🔝
Model Call Girl in Bikash Puri Delhi reach out to us at 🔝9953056974🔝
 
Call Girls in Dwarka Mor Delhi Contact Us 9654467111
Call Girls in Dwarka Mor Delhi Contact Us 9654467111Call Girls in Dwarka Mor Delhi Contact Us 9654467111
Call Girls in Dwarka Mor Delhi Contact Us 9654467111
 
The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13
 

Featured

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data ScienceChristy Abraham Joy
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

MapKit iPhone App: Create Maps and Parse Earthquake Data

  • 1. Maps on the iPhone Using MapKit for Fun and Profit Wednesday, September 30, 2009 1
  • 2. Add A MKMapView Wednesday, September 30, 2009 2
  • 3. Tweak Parameters Show the blue breathing dot Then Build and Go... Wednesday, September 30, 2009 3
  • 4. And Bada-Boom A Map App Wednesday, September 30, 2009 4
  • 5. But we want more, like the breathing Blue Dot Wednesday, September 30, 2009 5
  • 6. Where we are Headed ‘Right’ Action - Details ‘Left’ Action - Shake Map Animated ‘Breathing’ Wednesday, September 30, 2009 6
  • 7. Stuff To Do • View Based Project • Parse XML from USGS • Create Earthquakes • Store Earthquakes • Add Annotations • Provide Annotation Views • Respond to Events Wednesday, September 30, 2009 7
  • 8. View Based Project Connect the MapView to our VC Wednesday, September 30, 2009 8
  • 9. Parse XML NSOperationQueue operation NSOperation thread parseForData: addOperation: Parse XML EarthquakeParser initWithContentsOfURL: parse invokeOnMainThread: didStartElement: foundCharcters: didEndElement: NSXMLParser event loop addEarthquake: parserFinished EarthquakeParserDelegate (MapQuakesViewController) Don’t block the main event thread! Wednesday, September 30, 2009 9
  • 10. NSOperationQueue operation NSOperation thread Parse XML parseForData: addOperation: EarthquakeParser Kick Off The Parse parseForData: is on an alternate thread, won’t block event thread while downloading the XML Wednesday, September 30, 2009 10
  • 11. EarthquakeParser initWithContentsOfURL: Parse XML parse NSXMLParser Parse XML on the Each XML Event comes to the parser’s delegate on the alternate thread alternate thread Wednesday, September 30, 2009 11
  • 12. NSXMLParser Kick-off - (BOOL)parseForData { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; NSURL *url = [NSURL URLWithString:feedURLString]; Parse XML BOOL success = NO; NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url]; [parser setDelegate:self]; [parser setShouldProcessNamespaces:NO]; [parser setShouldReportNamespacePrefixes:NO]; [parser setShouldResolveExternalEntities:NO]; success = [parser parse]; NSError *parseError = [parser parserError]; if (parseError) { ! NSLog(@"parse error = %@", parseError); } [parser release]; [pool drain]; return success; } Wednesday, September 30, 2009 12
  • 13. Create Earthquakes EarthquakeParser didStartElement: foundCharcters: didEndElement: NSXMLParser Parse XML on the Each XML Event comes to the parser’s delegate on the alternate thread alternate thread Wednesday, September 30, 2009 13
  • 14. Entry Element starts and Earthquake - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName Create Earthquakes attributes:(NSDictionary *)attributeDict { if(nil != qName) { elementName = qName; // swap for the qName if we have a name space } if ([elementName isEqualToString:@"entry"]) { self.currentEarthquake = [[[Earthquake alloc] init] autorelease]; } else if([elementName isEqualToString:@"link"]) { // ignore the related content and just grab the alternate if ([[attributeDict valueForKey:@"rel"] isEqualToString:@"alternate"]) { NSString *link = [attributeDict valueForKey:@"href"]; self.currentEarthquake.detailsURL = [NSString stringWithFormat:@"http://earthquake.usgs.gov/%@", link]; } } else if([elementName isEqualToString:@"title"] || [elementName isEqualToString:@"updated"] || [elementName isEqualToString:@"id"] || [elementName isEqualToString:@"georss:point"] || [elementName isEqualToString:@"georss:elev"]) { self.propertyValue = [NSMutableString string]; } else { self.propertyValue = nil; } } Wednesday, September 30, 2009 14
  • 15. EarthquakeParser Back to the Main Thread Store Earthquakes invokeOnMainThread: event loop addEarthquake: EarthquakeParserDelegate Let the main thread know an earthquake was (MapQuakesViewController) found by pushing the addEarthquake: and parserFinished methods onto the main thread Wednesday, September 30, 2009 15
  • 16. Ending Element Pushes Earthquake Store Earthquakes - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { ... } else if([elementName isEqualToString:@"entry"]) { Earthquake *quake = self.currentEarthquake; self.currentEarthquake = nil; [(id)[self delegate] performSelectorOnMainThread:@selector(addEarthquake:) withObject:quake waitUntilDone:NO]; } } Wednesday, September 30, 2009 16
  • 17. MapQuakesVC holds the Earthquakes Store Earthquakes - (void)addEarthquake:(Earthquake *)earthquake { [self.earthquakes addObject:earthquake]; } Wednesday, September 30, 2009 17
  • 18. EarthquakeParser Back to the Main Thread Add Annotations invokeOnMainThread: event loop parserFinished EarthquakeParserDelegate Once all the XML is parsed we tell the delegate (MapQuakesViewController) which displays the earthquakes in the form of an annotation. Wednesday, September 30, 2009 18
  • 19. Back to the Main Thread Again Add Annotations - (void)parserDidEndDocument:(NSXMLParser *)parser { [(id)[self delegate] performSelectorOnMainThread:@selector(parserFinished) withObject:nil waitUntilDone:NO]; [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; [self autorelease]; } Wednesday, September 30, 2009 19
  • 20. Display Earthquakes as Annotations Add Annotations - (void)parserFinished { [self displayEarthquakes]; } Wednesday, September 30, 2009 20
  • 21. Remove Old Annotations - (void)displayEarthquakes { Add Annotations [self removeAnnotations]; NSArray *visibleQuakes = [self sortAndFilterEarthquakes]; // limit the numer to 100 if(visibleQuakes.count > 100) { // remove the earthquakes from the top of the // list until we are down to 100 NSUInteger removeCount = visibleQuakes.count - 100; NSRange keepers = {removeCount, 100}; // location and length visibleQuakes = [visibleQuakes subarrayWithRange:keepers]; } for(Earthquake *earthquake in visibleQuakes) { EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation annotationWithEarthquake:earthquake]; [self.mapView addAnnotation:eqAnn]; } } Wednesday, September 30, 2009 21
  • 22. Find Visible Quakes Sorted by Magnitude - (void)displayEarthquakes { Add Annotations [self removeAnnotations]; NSArray *visibleQuakes = [self sortAndFilterEarthquakes]; // limit the numer to 100 if(visibleQuakes.count > 100) { // remove the earthquakes from the top of the // list until we are down to 100 NSUInteger removeCount = visibleQuakes.count - 100; NSRange keepers = {removeCount, 100}; // location and length visibleQuakes = [visibleQuakes subarrayWithRange:keepers]; } for(Earthquake *earthquake in visibleQuakes) { EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation annotationWithEarthquake:earthquake]; [self.mapView addAnnotation:eqAnn]; } } Wednesday, September 30, 2009 22
  • 23. Limit Earthquakes to 100 - (void)displayEarthquakes { Add Annotations [self removeAnnotations]; NSArray *visibleQuakes = [self sortAndFilterEarthquakes]; // limit the numer to 100 if(visibleQuakes.count > 100) { // remove the earthquakes from the top of the // list until we are down to 100 NSUInteger removeCount = visibleQuakes.count - 100; NSRange keepers = {removeCount, 100}; // location and length visibleQuakes = [visibleQuakes subarrayWithRange:keepers]; } for(Earthquake *earthquake in visibleQuakes) { EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation annotationWithEarthquake:earthquake]; [self.mapView addAnnotation:eqAnn]; } } Wednesday, September 30, 2009 23
  • 24. Find and Display Earthquakes - (void)displayEarthquakes { Add Annotations [self removeAnnotations]; NSArray *visibleQuakes = [self sortAndFilterEarthquakes]; // limit the numer to 100 if(visibleQuakes.count > 100) { // remove the earthquakes from the top of the // list until we are down to 100 NSUInteger removeCount = visibleQuakes.count - 100; NSRange keepers = {removeCount, 100}; // location and length visibleQuakes = [visibleQuakes subarrayWithRange:keepers]; } for(Earthquake *earthquake in visibleQuakes) { EarthquakeAnnotation *eqAnn = [EarthquakeAnnotation annotationWithEarthquake:earthquake]; [self.mapView addAnnotation:eqAnn]; } } Wednesday, September 30, 2009 24
  • 25. Remove old Earthquake Annotations Add Annotations - (void) removeAnnotations { // remove the old annotations but // don't modify the array while iterating NSArray *annotationsCopy = [self.mapView.annotations copy]; for(id annotation in annotationsCopy) { if([[annotation class] isSubclassOfClass:[EarthquakeAnnotation class]]) { [self.mapView removeAnnotation:annotation]; } } [annotationsCopy release]; } Wednesday, September 30, 2009 25
  • 26. Filter Visible Earthquakes - (NSArray *)sortAndFilterEarthquakes { Add Annotations // find the visible earthquakes MKCoordinateRegion region = [self.mapView region]; LocationBoundingBox bbox = LocationBoundingBoxMake(region.center, region.span); NSPredicate *latPred = [NSPredicate predicateWithFormat: @"latitude BETWEEN {%@, %@}", [NSNumber numberWithFloat:bbox.min.latitude], [NSNumber numberWithFloat:bbox.max.latitude]]; NSPredicate *lonPred = [NSPredicate predicateWithFormat: @"longitude BETWEEN {%@, %@}", [NSNumber numberWithFloat:bbox.min.longitude], [NSNumber numberWithFloat:bbox.max.longitude]]; NSArray *predicates = [NSArray arrayWithObjects:latPred, lonPred, nil]; NSPredicate *locationPred = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; NSArray *quakes = [self.earthquakes filteredArrayUsingPredicate:locationPred]; NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"magnitude" ascending:YES]; NSArray *descriptors = [NSArray arrayWithObject:descriptor]; NSArray *sortedEarthquakes = [quakes sortedArrayUsingDescriptors:descriptors]; [descriptor release]; return sortedEarthquakes; } Wednesday, September 30, 2009 26
  • 27. Sort Earthquakes - (NSArray *)sortAndFilterEarthquakes { Add Annotations // find the visible earthquakes MKCoordinateRegion region = [self.mapView region]; LocationBoundingBox bbox = LocationBoundingBoxMake(region.center, region.span); NSPredicate *latPred = [NSPredicate predicateWithFormat: @"latitude BETWEEN {%@, %@}", [NSNumber numberWithFloat:bbox.min.latitude], [NSNumber numberWithFloat:bbox.max.latitude]]; NSPredicate *lonPred = [NSPredicate predicateWithFormat: @"longitude BETWEEN {%@, %@}", [NSNumber numberWithFloat:bbox.min.longitude], [NSNumber numberWithFloat:bbox.max.longitude]]; NSArray *predicates = [NSArray arrayWithObjects:latPred, lonPred, nil]; NSPredicate *locationPred = [NSCompoundPredicate andPredicateWithSubpredicates:predicates]; NSArray *quakes = [self.earthquakes filteredArrayUsingPredicate:locationPred]; NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"magnitude" ascending:YES]; NSArray *descriptors = [NSArray arrayWithObject:descriptor]; NSArray *sortedEarthquakes = [quakes sortedArrayUsingDescriptors:descriptors]; [descriptor release]; return sortedEarthquakes; } Wednesday, September 30, 2009 27
  • 28. Provide Annotation Views EarthquakeParserDelegate (MapQuakesViewController) addAnnotation: viewForAnnotation: MKMapViewDelegate (MapQuakesViewController) delegate Provides Annotation View Wednesday, September 30, 2009 28
  • 29. Return nil for user Provide Annotation Views location - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *view = nil; if(annotation != mapView.userLocation) { !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation; !! view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"]; !! if(nil == view) { view = [[[EarthquakeAnnotationView alloc] initWithAnnotation:eqAnn reuseIdentifier:@"earthquakeLoc"] autorelease]; !! } view.annotation = annotation; [view setCanShowCallout:YES]; UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; [view setRightCalloutAccessoryView:button]; } return view; } Wednesday, September 30, 2009 29
  • 30. Provide Annotation Views Reuse Annotation Views - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *view = nil; if(annotation != mapView.userLocation) { !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation; !! view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"]; !! if(nil == view) { view = [[[EarthquakeAnnotationView alloc] initWithAnnotation:eqAnn reuseIdentifier:@"earthquakeLoc"] autorelease]; !! } view.annotation = annotation; [view setCanShowCallout:YES]; UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; [view setRightCalloutAccessoryView:button]; } return view; } Wednesday, September 30, 2009 30
  • 31. Create if no re-useable Provide Annotation Views views exist - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *view = nil; if(annotation != mapView.userLocation) { !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation; !! view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"]; !! if(nil == view) { view = [[[EarthquakeAnnotationView alloc] initWithAnnotation:eqAnn reuseIdentifier:@"earthquakeLoc"] autorelease]; !! } view.annotation = annotation; [view setCanShowCallout:YES]; UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; [view setRightCalloutAccessoryView:button]; } return view; } Wednesday, September 30, 2009 31
  • 32. Provide Annotation Views Congure View - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation { MKAnnotationView *view = nil; if(annotation != mapView.userLocation) { !! EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation*)annotation; !! view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"earthquakeLoc"]; !! if(nil == view) { view = [[[EarthquakeAnnotationView alloc] initWithAnnotation:eqAnn reuseIdentifier:@"earthquakeLoc"] autorelease]; !! } view.annotation = annotation; [view setCanShowCallout:YES]; UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; [view setRightCalloutAccessoryView:button]; } return view; } Wednesday, September 30, 2009 32
  • 33. Custom Provide Annotation Views MKAnnotationView Subclass EarthquakeAnnotationView Wednesday, September 30, 2009 33
  • 34. Congure the Provide Annotation Views Annotation View - (void)setAnnotation:annotation { [super setAnnotation:annotation]; [self.layer.sublayers makeObjectsPerformSelector: @selector(removeFromSuperlayer)]; self.frame = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); self.earthquake = [(EarthquakeAnnotation *)annotation earthquake]; [self addBreathingLayer]; [self addDarkCircleLayer]; } Wednesday, September 30, 2009 34
  • 35. Provide Annotation Views Shape Layer - (void) addBreathingLayer { self.circleLayer = [CAShapeLayer layer]; CGColorRef color = [self newFillColor]; self.circleLayer.fillColor = color; CGColorRelease(color); color = [self newStrokeColor]; self.circleLayer.strokeColor = color; CGColorRelease(color); self.circleLayer.lineWidth = 1.0f; CGMutablePathRef path = CGPathCreateMutable(); CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); self.circleLayer.frame = square; CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; pathAnimation.duration = 1.5f; pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; pathAnimation.repeatCount = 1E100f; pathAnimation.autoreverses = YES; self.circleLayer.actions = [NSDictionary dictionaryWithObject:pathAnimation forKey:@"path"]; [self.layer addSublayer:self.circleLayer]; } Wednesday, September 30, 2009 35
  • 36. Provide Annotation Views Breathing Animation - (void) addBreathingLayer { self.circleLayer = [CAShapeLayer layer]; CGColorRef color = [self newFillColor]; self.circleLayer.fillColor = color; CGColorRelease(color); color = [self newStrokeColor]; self.circleLayer.strokeColor = color; CGColorRelease(color); self.circleLayer.lineWidth = 1.0f; CGMutablePathRef path = CGPathCreateMutable(); CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); self.circleLayer.frame = square; CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; pathAnimation.duration = 1.5f; pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; pathAnimation.repeatCount = 1E100f; pathAnimation.autoreverses = YES; self.circleLayer.actions = [NSDictionary dictionaryWithObject:pathAnimation forKey:@"path"]; [self.layer addSublayer:self.circleLayer]; } Wednesday, September 30, 2009 36
  • 37. Selection Starts Provide Annotation Views Animation - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; if(YES == selected) { // animate the bottom shape's path CGRect square = CGRectMake(16.0f, 16.0f, 16.0f, 16.0f); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); EarthquakeParser *parser = [EarthquakeParser earthquakeParser]; parser.delegate = self; [parser getShakeMapForEarthquake:self.earthquake]; } else { [CATransaction begin]; [CATransaction setDisableActions:YES]; CGMutablePathRef path = CGPathCreateMutable(); CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); [CATransaction commit]; } } Wednesday, September 30, 2009 37
  • 38. De-Selection Stops Provide Annotation Views Animation - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; if(YES == selected) { // animate the bottom shape's path CGRect square = CGRectMake(16.0f, 16.0f, 16.0f, 16.0f); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); EarthquakeParser *parser = [EarthquakeParser earthquakeParser]; parser.delegate = self; [parser getShakeMapForEarthquake:self.earthquake]; } else { [CATransaction begin]; [CATransaction setDisableActions:YES]; CGMutablePathRef path = CGPathCreateMutable(); CGRect square = CGRectMake(0.0f, 0.0f, 48.0f, 48.0f); CGPathAddEllipseInRect(path, NULL, square); self.circleLayer.path = path; CGPathRelease(path); [CATransaction commit]; } } Wednesday, September 30, 2009 38
  • 39. Selected Animation Provide Annotation Views Wednesday, September 30, 2009 39
  • 40. ‘Right’ Detail Respond To Events ‘Left’ Shake Map Wednesday, September 30, 2009 40
  • 41. Open The Web Page Respond To Events - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { NSURL *url = nil; EarthquakeAnnotation *eqAnn = (EarthquakeAnnotation *)[view annotation]; if(view.rightCalloutAccessoryView == control) { NSString *urlString = [eqAnn.earthquake.detailsURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; url = [NSURL URLWithString:urlString]; } else { NSString *urlString = [eqAnn.earthquake.shakeMapURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; url = [NSURL URLWithString:urlString]; } [[UIApplication sharedApplication] openURL:url]; } Wednesday, September 30, 2009 41
  • 42. Where To Now? • Your data will likely have more interesting selection criteria, exploit it • The ‘detail’ from right and left buttons can do lots more interesting stuff • USGS Provides KML les for shake maps • Use Core Animation in the right or left buttons Wednesday, September 30, 2009 42
  • 43. Summary • Filtering your Annotations is important if you have lots of data • It’s easy to build your own custom annotation views and add Core Animation to them Wednesday, September 30, 2009 43
  • 44. Thanks! Pragmatic iPhone Studio Wednesday, September 30, 2009 44