简体   繁体   中英

Return User's State as an NSString with reverseGeocodeLocation

I am trying to simply return a user's state. I understand that I need to use reverseGeocodeLocation. I would like to return the state as an NSString in the same way that I am returning the user latitude below:

- (NSString *)getUserLatitude
{
NSString *userLatitude = [NSString stringWithFormat:@"%f", 
locationManager.location.coordinate.latitude];
return userLatitude;
}

I currently have this code, but I cannot get it to work. It may be because I am using (void). I am just a bit lost.

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

CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
[geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, 
NSError *error) {
    for (CLPlacemark * placemark in placemarks) {
        NSString *userState = [placemark locality];

    return userState;

    }
}];
}

Anyone have any ideas? Thank you!

You have to do something with the retrieved locality in the completion block. This code is executed asynchronously long after the method (with void return) has returned itself.

Usually you would call some sort of method on your own view controller or model class that passes the retrieved information.

Replace the return userState , it does not match the return type of the block.

Instead put something like:

[myViewController didFinishGettingState:userState];

You should look into block and GCD basics so that you can appreciate how this asynchnonicity works.

You are probably not understanding the way your completionHandler is working. The reverseGeocodeLocation:completionHandler: takes an handler, which is a function that will be executed when the lookup is completed and invoked with the placemarks and error as parameters.

What you have to do is to perform something meaningful in that block. I would start checking whether any error occurred, then I would call a method for failing or success as follows

[geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
    if (error != nil) {
        // Something bad happened...
        [self didFailRetrievingUserState:error];
    } else {
        // Check whether the placemark retrieved is unique
        if (placemarks.count > 1) {
           NSMutableArray * states = [NSMutableArray array];
           for (CLPlacemark * placemark in placemarks) {
               NSString * userState = [placemark locality];
               [states addObject:userState];
           }
           [self didFinishRetrievingUserStates:states];
        } else {
           [self didFinishRetrievingUserState:[placemarks[0] locality]];
        }
    }
}];

Then of course you need to implement the three methods we are calling in the block above

- (void)didFailRetrievingUserState:(NSError *)error {
  // Show error
}

- (void)didFinishRetrievingUserStates:(NSArray *)userStates {
  // Do something reasonable with the multiple possible values 
}

- (void)didFinishRetrievingUserState:(NSString *)userState {
  // Do something reasonable with the only result you have
}

Clearly the above code is meant as a suggestion. You can make different decisions, like for instance handling all the logic inside the handler block, or not discriminating between the unique/not unique cases.

In general it's just important that you understand that the handler block is not supposed to return anything since it's a void function. It's just supposed to do something, and this something may be invoking your "delegate" methods as defined in the example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM