Google map 也提供了一個類似的服務,是訪問一個 google map 的 api,這里試圖封裝了 google map 的服務。使使用 apple 和 google 的服務的接口基本一致,替換起來很容易。Google map 的這個服務在中國的狀態比 apple 稍微好一些,但也有不穩定的時候。我猜想,apple 也許是使用 google 的服務封裝了自己的 MKReverseGeocoder。若是如此,這里的嘗試也就沒有什么意義了。
DOUHttpRequest 是對 ASIHTTPRequest 的一個簡單封裝。這些代碼可以 繼承自 MKReverseGeocoder。這樣,使用方法就和 MKReverseGeocoder 一樣了。
static NSString* kGeoServerUrl = @"http://maps.google.com/maps/api/geocode/json?latlng=%f,%f&sensor=true&language=en";
static NSString* kLatitudeUserInfoKey = @"latitudeUserInfoKey";
static NSString* kLongitudeUserInfoKey = @"longitudeUserInfoKey";
//
// It's tje solution for replacing MKReverseGeocoder that has problem in China.
//
- (void)startedReverseGeoderWithLatitude:(double)latitude longitude:(double)longitude {
NSString *url = [NSString stringWithFormat:kGeoServerUrl, latitude, longitude];
DOUHttpRequest *req = [DOUHttpRequest requestWithURL:[NSURL URLWithString:url] target:self];
NSNumber *lat = [NSNumber numberWithDouble:latitude];
NSNumber *lon = [NSNumber numberWithDouble:longitude];
req.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:lat, kLatitudeUserInfoKey, lon, kLongitudeUserInfoKey, nil];
DOUService *service = [DOUService sharedInstance];
[service addRequest:req];
}
- (NSDictionary *)addressDictionary:(NSObject *)obj {
NSArray* ary = nil;
if (IS_INSTANCE_OF(obj, NSDictionary)) {
NSObject* data = [(NSDictionary*)obj objectForKey:@"results"];
if (IS_INSTANCE_OF(data, NSArray)) {
ary = (NSArray*)data;
NSDictionary *dic = [ary objectAtIndex:0];
NSArray *addressComps = [dic objectForKey:@"address_components"];
//NSString *streetNumber = @"";
NSString *route = @"";
NSString *locality = @"";
NSString *country = @"";
for (NSDictionary *comp in addressComps) {
NSArray *types = [comp objectForKey:@"types"];
NSString *type = [types objectAtIndex:0];
// if ([type isEqualToString:@"street_number"]) {
// streetNumber = [comp objectForKey:@"long_name"];
// }
if ([type isEqualToString:@"route"]) {
route = [comp objectForKey:@"long_name"];
}
if ([type isEqualToString:@"locality"]) {
locality = [comp objectForKey:@"long_name"];
}
if ([type isEqualToString:@"country"]) {
country = [comp objectForKey:@"long_name"];
}
}
NSDictionary *addressDic = [NSDictionary dictionaryWithObjectsAndKeys:route, kABPersonAddressStreetKey,
locality, kABPersonAddressCityKey,
country, kABPersonAddressCountryKey, nil];
return addressDic;
}
}
return nil;
}
- (void)requestFinished:(DOUHttpRequest *)req {
NSError *error = [req error];
if (!error) {
DebugLog(@"str:%@", [req responseString]);
NSObject *obj = [[req responseString] JSONValue];
NSDictionary *addressDic = [self addressDictionary:obj];
CLLocationCoordinate2D coordinate;
coordinate.latitude = [[req.userInfo objectForKey:kLatitudeUserInfoKey] doubleValue];
coordinate.longitude = [[req.userInfo objectForKey:kLongitudeUserInfoKey] doubleValue];
MKPlacemark *placemark = [[[MKPlacemark alloc] initWithCoordinate:coordinate
addressDictionary:addressDic] autorelease];
[self reverseGeocoder:nil didFindPlacemark:placemark];
}
}
- (void)requestFailed:(DOUHttpRequest *)req {
[self reverseGeocoder:nil didFailWithError:[req error]];
}
#pragma mark - MKReverseGeocoderDelegate
static NSString * const AppleLanguagesKey = @"AppleLanguages";
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {
NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:AppleLanguagesKey];
NSString *currentLanguage = [array objectAtIndex:0];
// set current language as english
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"zh-Hans", nil]
forKey:AppleLanguagesKey];
NSString *local = [placemark.locality lowercaseString];
[AppContext sharedInstance].currentCityUid = local;
// reset current language
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:currentLanguage, nil]
forKey:AppleLanguagesKey];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {
TraceLog(@"reverseGeocoder :%@", [error localizedDescription]);
}
static NSString* kLatitudeUserInfoKey = @"latitudeUserInfoKey";
static NSString* kLongitudeUserInfoKey = @"longitudeUserInfoKey";
//
// It's tje solution for replacing MKReverseGeocoder that has problem in China.
//
- (void)startedReverseGeoderWithLatitude:(double)latitude longitude:(double)longitude {
NSString *url = [NSString stringWithFormat:kGeoServerUrl, latitude, longitude];
DOUHttpRequest *req = [DOUHttpRequest requestWithURL:[NSURL URLWithString:url] target:self];
NSNumber *lat = [NSNumber numberWithDouble:latitude];
NSNumber *lon = [NSNumber numberWithDouble:longitude];
req.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:lat, kLatitudeUserInfoKey, lon, kLongitudeUserInfoKey, nil];
DOUService *service = [DOUService sharedInstance];
[service addRequest:req];
}
- (NSDictionary *)addressDictionary:(NSObject *)obj {
NSArray* ary = nil;
if (IS_INSTANCE_OF(obj, NSDictionary)) {
NSObject* data = [(NSDictionary*)obj objectForKey:@"results"];
if (IS_INSTANCE_OF(data, NSArray)) {
ary = (NSArray*)data;
NSDictionary *dic = [ary objectAtIndex:0];
NSArray *addressComps = [dic objectForKey:@"address_components"];
//NSString *streetNumber = @"";
NSString *route = @"";
NSString *locality = @"";
NSString *country = @"";
for (NSDictionary *comp in addressComps) {
NSArray *types = [comp objectForKey:@"types"];
NSString *type = [types objectAtIndex:0];
// if ([type isEqualToString:@"street_number"]) {
// streetNumber = [comp objectForKey:@"long_name"];
// }
if ([type isEqualToString:@"route"]) {
route = [comp objectForKey:@"long_name"];
}
if ([type isEqualToString:@"locality"]) {
locality = [comp objectForKey:@"long_name"];
}
if ([type isEqualToString:@"country"]) {
country = [comp objectForKey:@"long_name"];
}
}
NSDictionary *addressDic = [NSDictionary dictionaryWithObjectsAndKeys:route, kABPersonAddressStreetKey,
locality, kABPersonAddressCityKey,
country, kABPersonAddressCountryKey, nil];
return addressDic;
}
}
return nil;
}
- (void)requestFinished:(DOUHttpRequest *)req {
NSError *error = [req error];
if (!error) {
DebugLog(@"str:%@", [req responseString]);
NSObject *obj = [[req responseString] JSONValue];
NSDictionary *addressDic = [self addressDictionary:obj];
CLLocationCoordinate2D coordinate;
coordinate.latitude = [[req.userInfo objectForKey:kLatitudeUserInfoKey] doubleValue];
coordinate.longitude = [[req.userInfo objectForKey:kLongitudeUserInfoKey] doubleValue];
MKPlacemark *placemark = [[[MKPlacemark alloc] initWithCoordinate:coordinate
addressDictionary:addressDic] autorelease];
[self reverseGeocoder:nil didFindPlacemark:placemark];
}
}
- (void)requestFailed:(DOUHttpRequest *)req {
[self reverseGeocoder:nil didFailWithError:[req error]];
}
#pragma mark - MKReverseGeocoderDelegate
static NSString * const AppleLanguagesKey = @"AppleLanguages";
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {
NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:AppleLanguagesKey];
NSString *currentLanguage = [array objectAtIndex:0];
// set current language as english
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"zh-Hans", nil]
forKey:AppleLanguagesKey];
NSString *local = [placemark.locality lowercaseString];
[AppContext sharedInstance].currentCityUid = local;
// reset current language
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:currentLanguage, nil]
forKey:AppleLanguagesKey];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {
TraceLog(@"reverseGeocoder :%@", [error localizedDescription]);
}