Обновите свойство с помощью Geocoder, чтобы получить фактический адрес пользователя, EXC_BAD_ACCESS

Я относительно новый разработчик iOS, и я имею дело с обработчиком завершения геокодера, я не понимаю, как обновить переменную с адресом, найденным геокодером, и сделать с ним что-то. В двух словах, я хочу, чтобы блок геокодера перестал использовать информацию в каком-то методе.

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"didUpdateToLocation: %@", newLocation);
    CLLocation *currentLocation = newLocation;

    if (currentLocation != nil) {
        longitudeLabel = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
        latitudeLabel = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
    }

    [locationManager stopUpdatingLocation];

    // Reverse Geocoding
    NSLog(@"Resolving the Address");
    __block NSString * **annotation**;
    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
        if (error == nil && [placemarks count] > 0) {
            placemark = [placemarks lastObject];
            NSLog(@"location  %@",addressLabel);*/
            **annotation**=[NSString stringWithFormat:@" %@, %@, %@",
                                placemark.locality,
                                placemark.administrativeArea,
                                placemark.country];
        }
    } ];
    NSLog(@"location  %@",annotation);
    NSString *text = self.toPostCell.postText.text;
    UIImage *image = self.toPostCell.selectedImage.image;
    [Persistence addPostToServerAddtext:text addimage:image addbeach:nil **location:annotation**];
    [NSThread sleepForTimeInterval:5.0];
    self.posts = [Persistence getPostsUpTo: self.cantPosts forBeach:nil];
    imageLoaded = NO;
    [self.tableView reloadData];

}

Я попробовал основную очередь отправки, и я не могу получить аннотацию и использовать ее в методе, после глубокого поиска в Интернете я немного запутался в потоках, очередях и порядке их выполнения. При запуске метода выдается исключение EXC_BAD_ACCESS при регистрации аннотации после блока....


person jandresrodriguez    schedule 19.11.2013    source источник
comment
Кстати, ваш код предполагает, что первое местоположение, полученное didUpdateToLocation, является точным. На практике при использовании устройства (а не симулятора) часто требуется несколько вызовов метода CLLocationManagerDelegate со все меньшими и меньшими значениями horizontalAccuracy (т. к определенному GPS местоположению). Возможно, это первое возвращенное местоположение достаточно точно для ваших целей, но я рекомендую вам протестировать ваше приложение на устройстве в реальных сценариях, чтобы убедиться в этом.   -  person Rob    schedule 19.11.2013


Ответы (2)


Метод reverseGeocodeLocation выполняется асинхронно, поэтому не следует ссылаться на annotation вне блока completionHandler. Строка annotation не была установлена ​​к моменту, когда вы переходите к этому коду после блока reverseGeocodeLocation.

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

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    NSLog(@"didUpdateToLocation: %@", newLocation);
    CLLocation *currentLocation = newLocation;

    if (currentLocation != nil) {
        longitudeLabel = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
        latitudeLabel = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
    }

    [locationManager stopUpdatingLocation];

    // Reverse Geocoding
    NSLog(@"Resolving the Address");

    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        NSLog(@"Found placemarks: %@, error: %@", placemarks, error);

        if (error == nil && [placemarks count] > 0) {
            placemark = [placemarks lastObject];
            NSLog(@"location  %@",addressLabel);*/
            NSString *annotation = [NSString stringWithFormat:@" %@, %@, %@",
                                    placemark.locality,
                                    placemark.administrativeArea,
                                    placemark.country];

            NSLog(@"location  %@",annotation);
            NSString *text = self.toPostCell.postText.text;
            UIImage *image = self.toPostCell.selectedImage.image;
            [Persistence addPostToServerAddtext:text addimage:image addbeach:nil location:annotation];

            // I'm not sure why you're sleeping 5 seconds, but if you really want to do 
            // something five seconds later you should probably `dispatch_after`, thus
            // instead of:
            //
            // [NSThread sleepForTimeInterval:5.0];
            //
            // you might want to do the following:

            double delayInSeconds = 5.0;
            dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
            dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                self.posts = [Persistence getPostsUpTo: self.cantPosts forBeach:nil];
                imageLoaded = NO;
                [self.tableView reloadData];
            });
        }
    } ];
}
person Rob    schedule 19.11.2013
comment
ваш ответ был очень полезен для меня, как я могу посоветовать, что фоновый поток завершен, т. Е. Я отправляю изображение в фоновом режиме с помощью mutipart, используя AFNetworking, и мне нужно, чтобы меня заметили, когда он завершен, чтобы обновить представление, снова консультируясь с бэкэнд ... - person jandresrodriguez; 21.11.2013
comment
@JuanAndresRodriguez Я понимаю, что addPostToServerAddtext выполняет этот асинхронный вызов AFNetworking? А, это объясняет таинственный пятисекундный код. Да, мы можем сделать намного лучше, чем это. Вы можете (а) добавить параметр блока в свой метод addPostToServerAddtext; и (b) вызвать этот блок из блока успеха вызова AFNetworking. Возможно, вы можете обновить свой вопрос с помощью существующей реализации addPostToServerAddtext, и тогда я смогу показать вам, как это делается. - person Rob; 21.11.2013
comment
stackoverflow.com/questions/20124242 / - person jandresrodriguez; 21.11.2013

По сути, не запуская приложение, вы пытаетесь зарегистрировать свое местоположение, но нет гарантии, что блок был запущен до того, как вы вызовете «NSLog».

Если вы хотите, чтобы лог не падал, делайте это так, внутри того же блока;

[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
    NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
    if (error == nil && [placemarks count] > 0) {
        placemark = [placemarks lastObject];
        NSLog(@"location  %@",addressLabel);*/
        **annotation**=[NSString stringWithFormat:@" %@, %@, %@",
                            placemark.locality,
                            placemark.administrativeArea,
                            placemark.country];
        NSLog(@"location  %@",annotation);
    }
} ];

Таким образом, вы можете убедиться, что «аннотация» была установлена ​​​​до регистрации, и избежать EXC_BAD_ADDRESS, возникающего в результате ссылки на нулевой указатель...

person Frederic Yesid Peña Sánchez    schedule 19.11.2013