Последние 2 часа я пытался реализовать метод класса CLGeocoder, который используется для обратного геокодирования местоположения.

Код, предоставленный для этого метода в документации Xcode в справочнике по классу CLGeocode, следующий:

- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler

Я пытался использовать это в своем коде, и мне не повезло. Итак, я просмотрел несколько старых вопросов о stackoverflow и нашел реализацию, которая в итоге сработала для меня.

Вот код, который мне подходит:

-(IBAction)gpsButton {

 CLGeocoder *geocoder = [[CLGeocoder alloc]init];

 [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error){

  CLPlacemark *placemark = placemarks[0];
  NSLog(@"Found %@", placemark.thoroughfare);

}

 ];

}

Я не понимаю, почему документация xcode включает (CLLocation *) и (CLGeocodeCompletionHandler), хотя это не совсем то, как должен выглядеть окончательный код.

Это просто пытается напомнить мне, что объект «location» должен быть экземпляром класса CLLocation, а объект «completionHandler» должен быть экземпляром класса CLGeocodeCompletionHandler?

Он пытается напомнить мне, что перед реализацией этого метода мне нужно создать и инициализировать объекты для класса CLLocation и CLGeocodeCompletionHandler, чтобы метод мог работать правильно? И если это так, то почему CLLocation имеет указатель в примере xcode, а CLGeocodeCompletionHandler - нет?

Я понимаю, что это вопрос «фундаментального» типа, но я просмотрел несколько своих ссылок, и то, как они объясняют вещи, на самом деле не помогает мне справиться с этой путаницей.

Спасибо вам за помощь.

0
user3117509 24 Дек 2013 в 06:54

2 ответа

Лучший ответ

Ты говоришь:

Я не понимаю, почему документация xcode включает (CLLocation *) и (CLGeocodeCompletionHandler), хотя это не совсем то, как должен выглядеть окончательный код.

Дело в том, что так выглядит окончательный код. Итак, как вы указываете, метод reverseGeocodeLocation:completionHandler: определяется как таковой:

- (void)reverseGeocodeLocation:(CLLocation *)location completionHandler:(CLGeocodeCompletionHandler)completionHandler;

Кроме того, если вы посмотрите на определение CLGeocodeCompletionHandler, он определяется как блок, который возвращает void и принимает два параметра, массив меток и объект NSError, например:

typedef void (^CLGeocodeCompletionHandler)(NSArray *placemarks, NSError *error);

Таким образом, ваш пример кода, приведенный ниже, точно соответствует этому определению:

[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error){

    CLPlacemark *placemark = placemarks[0];
    NSLog(@"Found %@", placemark.thoroughfare);

}];

Если вы спрашиваете, почему определение метода reverseGeocodeLocation:completionHandler: использует typedef CLGeocodeCompletionHandler, а не фактическое определение сложного блока, они делают это для упрощения кода. Да, это делает «завершение кода» Xcode немного менее полезным, но когда вы фактически пишете код, реализующий этот метод с параметром блока, это значительно упрощает вашу жизнь.

Когда вы начнете писать свои собственные методы, которые принимают параметры блоков и имеют классы, которые хранят эти блоки в свойствах, вы увидите, что использование typedef действительно является находкой, устраняя множество простых ошибок, возникающих из-за опечаток в действительно неудобный синтаксис блока.

Например, предположим, что вы хотите сохранить этот блок в переменной, а затем использовать эту переменную в своем вызове reverseGeocodeLocation. Поскольку у вас есть typedef, это очень просто:

CLGeocodeCompletionHandler customHandler = ^(NSArray *placemarks, NSError *error){
    CLPlacemark *placemark = placemarks[0];
    NSLog(@"Found %@", placemark.thoroughfare);
};

[geocoder reverseGeocodeLocation:currentLocation completionHandler:customHandler];

Без typedef вам пришлось бы прибегнуть к немного более громоздкому синтаксису:

void (^customHandler)(NSArray *, NSError *) = ^void(NSArray *placemarks, NSError *error) {
    CLPlacemark *placemark = placemarks[0];
    NSLog(@"Found %@", placemark.thoroughfare);
};

[geocoder reverseGeocodeLocation:currentLocation completionHandler:customHandler];

По общему признанию, это несколько надуманный пример, но по мере того, как вы используете все больше и больше блоков, вы начнете ценить простоту, которую предоставляет typedef, когда вам приходится снова и снова использовать одну и ту же подпись блока во всем коде. .

Итак, всякий раз, когда вы видите метод, который имеет настраиваемый блок typedef в качестве параметра, просто просмотрите еще один уровень детализации и взгляните на этот typedef, и все должно стать ясным.

1
Rob 24 Дек 2013 в 04:49

Что ж, CLLocation - это класс, который вам нужно инициализировать и перевернутьGeocode, но CLGeocodeCompletionHandler - это дескриптор callback-функции блока typedef. поэтому вам не нужно его инициализировать.

0
johnMa 24 Дек 2013 в 03:01