Пакетный геокод MKLocalSearchResponse

У меня есть настройка поиска, которая отображает ответ MKLocalSearchRequest в UITableVIew

Я хочу очистить все ответы от ответа каждого поиска. Вот мой пример достижения этой цели, вдохновленный этим постом " Несколько местоположений на карте" (с использованием MKMapItem и CLGeocoder)

Вот мой код

@interface ViewController () <UISearchBarDelegate,UISearchDisplayDelegate,UITextFieldDelegate>
@property (nonatomic, strong) UISearchDisplayController *searchController;
@property (nonatomic, strong) UISearchBar *searchBar;

@property (nonatomic, strong) MKLocalSearch *localSearch;
@property (nonatomic, strong) MKLocalSearchResponse *localSearchResponse;

@property (nonatomic, strong) NSArray *dirtyResponseArray;
@property (nonatomic, strong) NSMutableArray *geocodedResultsArray;
@end

@implementation ViewController

-(void)startSearch:(NSString *)searchString
{
    if (self.localSearch.searching)
        [self.localSearch cancel];

    MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
    request.naturalLanguageQuery = searchString;
    request.region = MKCoordinateRegionMake(self.currentLocation.coordinate, self.mapView.region.span);

    MKLocalSearchCompletionHandler completionHandler = ^(MKLocalSearchResponse *response, NSError *error){

        if (error != nil) return;

        else {
            self.dirtyResponseArray = response.mapItems;                
            [self operation];
            [self.searchController.searchResultsTableView reloadData];
            [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        }

        [self.searchDisplayController.searchResultsTableView reloadData];
    };

    if (self.localSearch != nil)
        self.localSearch = nil;

    self.localSearch = [[MKLocalSearch alloc] initWithRequest:request];
    [self.localSearch startWithCompletionHandler:completionHandler];
}

-(void)operation
{
    CLGeocoder *geocoder = [[CLGeocoder alloc]init];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    NSOperation *finalCompletionOperation = [NSBlockOperation blockOperationWithBlock:^{
        [MKMapItem openMapsWithItems:self.geocodedResultsArray launchOptions:nil];
        NSLog(@"Local Search Response To use in tableview =================== %@", self.geocodedResultsArray);
    }];

    NSOperation *previousCompletionHandler = nil;

    //Issue is probably right here. How should I handle the MKMapItem in the array?
    //NSString *address = [self.dirtyResponseArray valueForKey:@"address"][@"formattedAddress"]; ??

    for (NSString *address in self.dirtyResponseArray) {

        NSBlockOperation *geocodeRequest = [[NSBlockOperation alloc] init];
        if (previousCompletionHandler) [geocodeRequest addDependency:previousCompletionHandler];
        NSBlockOperation *geocodeCompletionHandler = [[NSBlockOperation alloc] init];
        [finalCompletionOperation addDependency:geocodeCompletionHandler];

        [geocodeRequest addExecutionBlock:^{ [geocoder geocodeAddressString:address 
                        completionHandler:^(NSArray *placemarks, NSError *error) 
        {
                [geocodeCompletionHandler addExecutionBlock:^{
                    if (error) NSLog(@"%@", error);

                    else if ([placemarks count] > 0)
                    {
                        CLPlacemark *geocodedPlacemark = [placemarks objectAtIndex:0];

                        MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:geocodedPlacemark.location.coordinate
                                                                       addressDictionary:geocodedPlacemark.addressDictionary];

                        MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
                        [mapItem setName:geocodedPlacemark.name];
                        [self.geocodedResultsArray addObject:mapItem];
                    }
                }];
                [queue addOperation:geocodeCompletionHandler];
            }];
        }];
        [queue addOperation:geocodeRequest];
        previousCompletionHandler = geocodeCompletionHandler;
    }
    [queue addOperation:finalCompletionOperation];
}
@end

Я не уверен, как обращаться с каждым MKMapItem. Прямо сейчас это бросает эту ошибку

 -[MKMapItem length]: unrecognized selector sent to instance 0x7f813c9c6200

1 ответ

Решение

CLGeocoder метод, geocodeAddressString, который упоминается в этом другом вопросе, предназначен для геокодирования адреса.

Но вы выполняете MKLocalSearch в определенном регионе, который возвращает MKMapItem объекты, которые уже геокодированы. В результате вы можете полностью удалить geocodeAddressString код из вашего примера кода.

На самом деле, это объясняет источник вашего исключения, что вы принимаете MKMapItem вернулся MKLocalSearchи пытается использовать его в качестве параметра строки поиска CLGeocoder метод geocodeAddressString (который используется только для поиска строковых представлений адресов).

В итоге, сделать локальный поиск и показать результаты в приложении "Карты" гораздо проще, чем вы предполагали выше. Все, что вам нужно сделать, это:

MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = searchString;
request.region = region;
MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];

[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
    [MKMapItem openMapsWithItems:response.mapItems launchOptions:nil];
}];

Или, если вы хотите показать это самостоятельно MKMapViewВы могли бы сделать что-то вроде

MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = searchString;
request.region = region;
MKLocalSearch *search = [[MKLocalSearch alloc] initWithRequest:request];

[search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
    for (MKMapItem *item in response.mapItems) {
        [self.mapView addAnnotation:item.placemark];
    }
}];

На практике в последнем примере, где вы показываете результаты в своем собственном виде карты, вы можете создать свой собственный класс аннотаций, чтобы иметь больший контроль над рендерингом представления аннотаций в viewForAnnotation метод. Но, надеюсь, это иллюстрирует основное наблюдение, что при использовании MKLocalSearch, вы не должны использовать CLGeocoder метод geocodeAddressString совсем.

Другие вопросы по тегам