title: Optimal way to add annotations to MKMapView
body: <p>I pull a list of address from a DB. Where the size of the list could be 0-n. But where n is usually 50-60. </p>
  
  <p>I am trying to discover the <em>optimal</em> way to add all of these locations to a map view. </p>
  
  <p>The method that I am currently using goes as follows. </p>
  
  <ol>
  <li><p>I create a mutableArray (annotations) to hold all of my annotations (I remove and add them back frequently so it is best to keep them all on hand for fast addition/removal). </p></li>
  <li><p>I run through my loaded list of addresses (from DB) passing the address to a reverse geocoder to obtain the lat and long. </p></li>
  <li><p>Check to see if the lat and long is 0,0 (meaning I was rate limited by google). </p></li>
  <li><p><strong>Y -</strong> If so I flag that there has been a rate ban and add @"" to the annotations array. It is essential to keep the annotations in order for proper reference when adding and removing.  </p></li>
  <li><p><strong>N -</strong> If not then I add that annotation to the map and the annotations array. </p></li>
  <li><p>IF there has been a rate ban, I run through the annotations array looking for @"", when one is found, proceed with steps 2-5. </p></li>
  </ol>
  
  <p>I recursively call this function (Step 5) until all annotation are added. But it seems inefficient. </p>
  
  <p>Has anyone discovered a way that would be more time and memory efficient? </p>
  
  <hr>
  
  <p>This is the initial call the kickoff the annotation loading:</p>
  
  <pre><code>- (void)addLocations {
  
      /*
       Setup an array to hold all annotations, this is done for fast removal/addition when filtering which happens often. So far, through testings, has shown to be the optimal way. 
      */
      annotations = [[NSMutableArray alloc] init];
  
      bool needsReload = NO;
  
      //Loop through all locations parsed from the DB
      for (int i = 0; i &lt; [[[[self appDelegate] rssParser]rssItems] count]; i++) {
  
          NSString *temp = [NSString stringWithFormat:@"%@, %@, %@", [[[[[self appDelegate]rssParser]rssItems] objectAtIndex:i] Address],  [[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i]City], [[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i]State]];
  
          CLLocationCoordinate2D tempLocation = [self addressLocation:temp];
  
  
          if (tempLocation.latitude == 0.0) {
  
              //We have been rate banned and flag for a re-run through locations. 
              [[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i] setLocation:nil];
  
              needsReload = YES;
  
              [annotations addObject:@""];
  
          } else {
  
              /*
               Set location of property. Done for property use in other locations of app. 
              */
              CLLocation *tempLoc = [[CLLocation alloc] initWithLatitude:tempLocation.latitude longitude:tempLocation.longitude];
              [[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i] setLocation:tempLoc];
  
              //Create new annotation with proper coordinates
              MapAnnotation *addAnnotation = [[MapAnnotation alloc] initWithCoordinate:tempLocation];
              addAnnotation.name = [[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i]Address];
  
              // Check to see if location has an image associated with it. 
              if ([[[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i] imageURLs] count] &gt; 0 )
                  addAnnotation.thumbURL = [[[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i] imageURLs] objectAtIndex:0];
              else
                  addAnnotation.thumbURL = nil;
  
              addAnnotation.tag = i;
  
              addAnnotation.description = [NSString stringWithFormat:@"%@, %@ | $%@",[[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i]City] , [[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i]State] ,[[[[[[self appDelegate]rssParser]rssItems] objectAtIndex:i] Deposit] stringByReplacingOccurrencesOfString:@".00" withString:@""]];
  
              //Add annotation to "annotations" array for fast addition/removal when filtering. 
              [annotations addObject:addAnnotation];
  
              [self._mapView addAnnotation:addAnnotation];
  
              //Doesn't seem necessary in ARC but somehow helps with memory on iPhone 3GS
              temp = nil;
              addAnnotation = nil;
          }
      }
  
      //Attempt to force a refresh so annotations show up. 
      [self._mapView setCenterCoordinate:self._mapView.centerCoordinate zoomLevel:ZOOM_LEVEL animated:NO];
  
      /*
        If there was a rate ban we need to run through the locations again to get proper coordinates
       */
      if (needsReload == YES) {
          //Sleep the thread to shake off rate ban from google. 
          [NSThread sleepForTimeInterval:2.0f];
          //Move to the background so user can begin interacting with app
          [self performSelectorInBackground:@selector(rateLimited) withObject:nil];
  
      } else {
          //All locations were property loaded so we can stop here. 
          [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
          self.radiusControl.hidden = NO;
      }
  }
  </code></pre>
  
  <p>If there was a rate ban we move to this to recursively called method to correctly obtain all coordinates. </p>
  
  <pre><code>- (void)rateLimited {
  
      /*
       Create an array to hold the newly loaded annotations. For some reason the map will only load annoations if I add this this way. Instead of adding them one at a time as done before. I suppose it has to do with some refresh issue. 
      */
      NSMutableArray *tempReload = [[NSMutableArray alloc] init];
  
      bool needsReload = NO;
  
      /*
       Run through the parsed list of property objects again looking for @""
       */
      for ( int i = 0; i &lt; [annotations count]; i++) {
  
          if ([[annotations objectAtIndex:i] isEqualToString:@""]) {
  
              Property *tempProp = (Property*) [[[self.appDelegate rssParser] rssItems] objectAtIndex:i];
  
              NSString *temp = [NSString stringWithFormat:@"%@, %@, %@", [tempProp Address],  [tempProp City], [tempProp State]];
  
              CLLocationCoordinate2D tempLocation = [self addressLocation:temp];
  
              //There was another rate ban so we need to run through list again. 
              if (tempLocation.latitude == 0.0) {
                  needsReload = YES;
  
              } else {
  
                  CLLocation *tempLoc = [[CLLocation alloc] initWithLatitude:tempLocation.latitude longitude:tempLocation.longitude];
  
                  [[[[[self appDelegate] rssParser]rssItems]objectAtIndex:i] setLocation:tempLoc];
  
                  MapAnnotation *addAnnotation = [[MapAnnotation alloc] initWithCoordinate:tempLocation];
                  addAnnotation.name = [tempProp Address];
                  if ([[tempProp imageURLs] count] &gt; 0 )
                      addAnnotation.thumbURL = [[tempProp imageURLs] objectAtIndex:0];
                  else
                      addAnnotation.thumbURL = nil;
  
                  //Have to keep tags corresponding to the inital listLocation assigned when DB is parsed from server. Done so when properties are added/removed they can be referenced correctly.
                  addAnnotation.tag = [tempProp listLocation];
  
                  //Set description
                  addAnnotation.description = [NSString stringWithFormat:@"%@, %@ | $%@",[tempProp City] , [tempProp State] ,[[tempProp Deposit] stringByReplacingOccurrencesOfString:@".00" withString:@""]];
  
                  //Repace the @"" with the proper annotation. 
                  [annotations replaceObjectAtIndex:i withObject:addAnnotation];
  
                  //Add annotation for bulk addition after loop as finished. 
                  [tempReload addObject:addAnnotation];
                  temp = nil;
                  addAnnotation = nil;
              }
          }
      }
  
      //Bulk add new annoations
      [self._mapView addAnnotations:tempReload];
  
      //If we need to reload, we recusivly call this method until all locations have proper coordinates. 
      if (needsReload == YES){
          needsReload = NO;
          tempReload = nil;
          //The recusive call
          [self rateLimited];
  
      } else {
          //All locations have property loaded now we can finish. *wew*
          [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
          self.radiusControl.hidden = NO;
      }
  
  }
  </code></pre>
  
  <hr>
  
  <p>Here is my method for reverse geocoding, perhaps someone may have a better way of going about it. </p>
  
  <pre><code>-(CLLocationCoordinate2D)addressLocation:(NSString*)_address {
  
      NSString *urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&amp;output=csv", 
                             [_address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
  
      NSError* error = nil;
      NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString ] encoding:NSASCIIStringEncoding error:&amp;error];
  
  
      NSArray *listItems = [locationString componentsSeparatedByString:@","];
  
      double latitude = 0.0;
      double longitude = 0.0;
  
      if([listItems count] &gt;= 4 &amp;&amp; [[listItems objectAtIndex:0] isEqualToString:@"200"]) {
          latitude = [[listItems objectAtIndex:2] doubleValue];
          longitude = [[listItems objectAtIndex:3] doubleValue];
      }
      else {
          NSLog(@"error");
      }
      CLLocationCoordinate2D location;
      location.latitude = latitude;
      location.longitude = longitude;
  
      return location;
  }
  </code></pre>