向MKMapView添加注释的最佳方式

时间:2012-02-28 06:06:56

标签: objective-c ios xcode optimization mkmapview

我从数据库中提取地址列表。列表的大小可以是0-n。但是n通常是50-60。

我正在尝试发现最佳方式,将所有这些位置添加到地图视图中。

我目前使用的方法如下。

  1. 我创建了一个mutableArray(注释)来保存我的所有注释(我删除并经常添加它们,所以最好保留它们以便快速添加/删除)。

  2. 我运行我加载的地址列表(来自DB)将地址传递给反向地理编码器以获取lat和long。

  3. 检查lat和long是否为0,0(意味着我受谷歌限制)。

  4. Y - 如果是这样,我会标记有禁止加价并将@“”添加到注释数组中。在添加和删除时,必须保留注释以便正确引用。

  5. N - 如果没有,那么我将该注释添加到地图和注释数组中。

  6. 如果有禁率,我会通过注释数组查找@“”,当找到一个时,继续执行步骤2-5。

  7. 我递归调用此函数(步骤5),直到添加所有注释。但似乎效率低下。

    是否有人发现了一种更有时间和内存效率的方法?


    这是初始调用启动注释加载:

    - (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 < [[[[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] > 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;
        }
    }
    

    如果有禁率,我们会移动到这个以递归方式调用方法来正确获取所有坐标。

    - (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 < [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] > 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;
        }
    
    }
    

    这是我的反向地理编码方法,也许有人可能有更好的方法来实现它。

    -(CLLocationCoordinate2D)addressLocation:(NSString*)_address {
    
        NSString *urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv", 
                               [_address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    
        NSError* error = nil;
        NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString ] encoding:NSASCIIStringEncoding error:&error];
    
    
        NSArray *listItems = [locationString componentsSeparatedByString:@","];
    
        double latitude = 0.0;
        double longitude = 0.0;
    
        if([listItems count] >= 4 && [[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;
    }
    

1 个答案:

答案 0 :(得分:0)

我会将每个位置设置为自己的对象,然后让该对象自己负责找出并设置自己的位置。 (如果出现问题,请在稍有延迟后重试)

然后你可以根据需要创建它们并让它们完成它们的工作 - 只有在它们让你知道它们准备好后才会在地图上显示它们。