Load only five annotations to MKMapVIew

半城伤御伤魂 提交于 2019-12-13 02:33:12

问题


I have a MKMapView, and I would like to know how I can find the nearest 5 annotations to the user, and only display them on the MKMapView.

My code currently is:

- (void)loadFiveAnnotations {
    NSString *string = [[NSString alloc] initWithContentsOfURL:url];
    string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    NSArray *chunks = [string componentsSeparatedByString:@";"];
    NSArray *keys = [NSArray arrayWithObjects:@"type", @"name", @"street", @"address1", @"address2", @"town", @"county", @"postcode", @"number", @"coffeeclub", @"latlong", nil];   
    // max should be a multiple of 12 (number of elements in keys array)
    NSUInteger max = [chunks count] - ([chunks count] % [keys count]);
    NSUInteger i = 0;

    while (i < max)
    {
        NSArray *subarray = [chunks subarrayWithRange:NSMakeRange(i, [keys count])];
        NSDictionary *dict = [[NSDictionary alloc] initWithObjects:subarray forKeys:keys];
        // do something with dict
        NSArray *latlong = [[dict objectForKey:@"latlong"] componentsSeparatedByString:@","];
        NSString *latitude = [[latlong objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        NSString *longitude = [[latlong objectAtIndex:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        CLLocationDegrees lat = [latitude floatValue];
        CLLocationDegrees longi = [longitude floatValue];
        Annotation *annotation = [[Annotation alloc] initWithCoordinate:CLLocationCoordinate2DMake(lat, longi)];
        annotation.title = [dict objectForKey:@"name"];
        annotation.subtitle = [NSString stringWithFormat:@"%@, %@, %@",[dict objectForKey:@"street"],[dict objectForKey:@"county"], [dict objectForKey:@"postcode"]];
        [mapView addAnnotation:annotation];
        [dict release];

        i += [keys count];
    }
}

回答1:


A long answer, already mostly written when Stephen Poletto posted and containing example code on how to use the built-in methods for sorting an array, so I though it was still worth posting though the essential answer is the same (ie, "pick the five closest for yourself, pass only those on"):

You're going to need to sort your annotations by distance for yourself, and submit only the closest five to the MKMapView. If you have two CLLocations then you can get the distance between them using the distanceFromLocation: method (which was getDistanceFrom: prior to iOS 3.2; that name is now deprecated).

So, for example, supposing your Annotation class had a method 'setReferenceLocation:' to which you pass a CLLocation and a getter 'distanceFromReferenceLocation' which returns the distance between the two, you could do:

// create and populate an array containing all potential annotations
NSMutableArray *allPotentialAnnotations = [NSMutableArray array];

for(all potential annotations)
{
    Annotation *annotation = [[Annotation alloc]
                                            initWithCoordinate:...whatever...];
    [allPotentialAnnotations addObject:annotation];
    [annotation release];
}

// set the user's current location as the reference location
[allPotentialAnnotations
      makeObjectsPerformSelector:@selector(setReferenceLocation:) 
      withObject:mapView.userLocation.location];

// sort the array based on distance from the reference location, by
// utilising the getter for 'distanceFromReferenceLocation' defined
// on each annotation (note that the factory method on NSSortDescriptor
// was introduced in iOS 4.0; use an explicit alloc, init, autorelease
// if you're aiming earlier)
NSSortDescriptor *sortDescriptor = 
              [NSSortDescriptor
                  sortDescriptorWithKey:@"distanceFromReferenceLocation" 
                  ascending:YES];

[allPotentialAnnotations sortUsingDescriptors:
                          [NSArray arrayWithObject:sortDescriptor]];

// remove extra annotations if there are more than five
if([allPotentialAnnotations count] > 5)
{
    [allPotentialAnnotations
               removeObjectsInRange:NSMakeRange(5, 
                           [allPotentialAnnotations count] - 5)];
}

// and, finally, pass on to the MKMapView
[mapView addAnnotations:allPotentialAnnotations];

Depending on where you're loading from, you made need to create a local store (in memory or on disk) for annotations and select the five nearest whenever the user moves. Either register yourself as a CLLocationManager delegate or key-value observe on the map view's userLocation property. If you have quite a lot of potential annotations then sorting all of them is a bit wasteful and you'd be better advised to use a quadtree or a kd-tree.




回答2:


First you'll need to grab the user's current location. You can build a CLLocationManager and register yourself as the delegate for location updates as follows:

locationManager = [[[CLLocationManager alloc] init] autorelease];
[locationManager setDelegate:self];
[locationManager startUpdatingLocation];

After setting yourself as the delegate, you'll receive the following callback:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation

Now that you have the user's location (newLocation), you can find the five closest annotations. There is a handy method in CoreLocation:

- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location

As you're iterating through your annotations, just store the five nearest locations. You can build a CLLocation out of the 'lat' and 'longi' variables you have using:

- (id)initWithLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude

Hope this helps!



来源:https://stackoverflow.com/questions/5223147/load-only-five-annotations-to-mkmapview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!