在地图视图中使用 CLGeocoder 而不是私有 API

Posted

技术标签:

【中文标题】在地图视图中使用 CLGeocoder 而不是私有 API【英文标题】:Using CLGeocoder instead of private API in map view 【发布时间】:2013-03-19 15:25:42 【问题描述】:

我使用 google API 来获取地理坐标。我一直在使用的代码如下

-(CLLocationCoordinate2D) getLocationFromAddressString:(NSString*) addressStr 

NSString *urlStr = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv",
                    [addressStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *locationStr = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlStr] encoding:NSStringEncodingConversionAllowLossy error:nil];
NSArray *items = [locationStr componentsSeparatedByString:@","];
double latitude = 0.0;
double longitude = 0.0;

//NSLog(@"items array %@", items);

if([items count] >= 4 && [[items objectAtIndex:0] isEqualToString:@"200"]) 
    latitude = [[items objectAtIndex:2] doubleValue];
    longitude = [[items objectAtIndex:3] doubleValue];

else 
    //NSLog(@"Address, %@ not found: Error %@",addressStr, [items objectAtIndex:0]);


CLLocationCoordinate2D location;
location.latitude = latitude;
location.longitude = longitude;
return location;

我希望使用CLGeocoder 代替google API 从地址字符串中获取位置坐标。

我一直在使用 CLGeocoder 从网上的例子中看到。我发现使用CLGeocoder 有点困难。我尝试使用CLGeocoder 而不对我之前的代码进行太多更改,这样我就不必对现有代码进行大的更改。

CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:addressStr completionHandler:^(NSArray *placemarks, NSError *error) 
    self.placemarksArray = placemarks;
    CLPlacemark *placeInfo = [placemarks objectAtIndex:0];
    NSString *latitudeString = [NSString stringWithFormat:@"%f",placeInfo.location.coordinate.latitude ];
    NSString *longitudeString = [NSString stringWithFormat:@"%f",placeInfo.location.coordinate.longitude ];
    NSLog(@"latitudeString %@", latitudeString);
    NSLog(@"longitudeString %@", longitudeString);

    _latitudes = placeInfo.location.coordinate.latitude;
    _longitudes = placeInfo.location.coordinate.longitude;
];
location.latitude = _latitudes;
location.longitude = _longitudes;
return location;

但是发生的情况是,地图视图在块执行之前被加载。在这种情况下,不会返回位置的确切值。

我的问题是:

    是否可以使用CLGeocoder,而无需对我之前的代码进行太多更改。或者我是否需要改变整个结构。 从我尝试的第二个代码块中,我做错了什么以及如何纠正它?

编辑:上面的方法是从viewDidLoad调用的

CLLocationCoordinate2D mapCenter = [self getLocationFromAddressString:fullAddress];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
            [annotationPoint setCoordinate:mapCenter];
            [annotationPointsArray addObject:annotationPoint];
addAnnotation = [[[MyAddressAnnotation alloc] initWithCoordinate:mapCenter title:firstName SubTitle:lastName]autorelease];

 [mapView addAnnotation:addAnnotation];

这在从 getGeoLocation 方法获取CLLocationCoordinate2D 纬度和经度值后执行。

【问题讨论】:

好的,您似乎正在从getLocationFromAddressString 获取location 并创建注释。您应该 (a) 更改 getLocationFromAddressString 以返回 void 和 (b) 然后将创建注释的代码放在 geocodeAddressString 完成块中。 我按照你的建议走。 【参考方案1】:

CLGeocoder 是异步发生的(事实上它是在一个块中完成的),因此 _latitudes_longitudes 在方法本身返回时没有设置。因此,很可能,是的,需要对您的代码进行一些轻微的重组。我们很难给出建议,因为我们没有看到调用这个例程的代码。最重要的是,您必须重构该代码,以便您可以调用 geocodeAddressString 中的 completionHandler,而不是返回 location

查看您修改后的代码,您的viewDidLoad 似乎正在获取位置坐标并创建注释。只需在地理编码块中添加注释inside

因此:

-(CLLocationCoordinate2D) geocodeAddressString:(NSString*)addressStr title:(NSString *)title subtitle:(NSString *)subtitle

    CLGeocoder *geocoder = [[[CLGeocoder alloc] init] autorelease];
    [geocoder geocodeAddressString:addressStr completionHandler:^(NSArray *placemarks, NSError *error) 
        self.placemarksArray = placemarks;
        CLPlacemark *placeInfo = [placemarks objectAtIndex:0];

        id<MKAnnotation> annotation = [[[MyAddressAnnotation alloc] initWithCoordinate:placeInfo.location.coordinate 
                                                                                 title:title
                                                                              SubTitle:subtitle] autorelease];

        [self.mapView addAnnotation:addAnnotation];
    ];

然后,viewDidLoad 会这样称呼它:

[self geocodeAddressString:fullAddress title:firstName subtitle:lastName]; 

【讨论】:

我的一个问题是关于标题和副标题信息。看来,我可以将此数据传递给注释对象的唯一方法是通过地址字符串参数?还是有更好的方法? @XaviValero 只需在方法中添加额外的参数即可。请参阅修改后的答案。【参考方案2】:

没什么神奇的,但你必须在你的街区里戳你的地图视图:

self.mapView.centerCoordinate = placeInfo.location.coordinate //or equivalent of this, like latitudes and longitudes change

如果你想避免mapview被绘制两次,你需要拦截MKMapview(特别是mapViewWillStartLoadingMap)的事件,在你的代码中实现它们,并放置适当的标志以避免地图被绘制直到时间倒转地理编码块尚未执行。

【讨论】:

【参考方案3】:

试试这个答案。

调用方法有部分延迟(即 2 秒)。

[self performSelector:@selector(geoCodeUsingAddress:) withObject:userAddress afterDelay:2.0];

调用GetCurrentLocation函数

- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)addressStr

    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:addressStr completionHandler:^(NSArray *placemarks, NSError *error) 
       self.placemarksArray = placemarks;
       CLPlacemark *placeInfo = [placemarks objectAtIndex:0];

       NSString *latitudeString = [NSString stringWithFormat:@"%f",placeInfo.location.coordinate.latitude ];
       NSString *longitudeString = [NSString stringWithFormat:@"%f",placeInfo.location.coordinate.longitude ];

       NSLog(@"latitudeString %@", latitudeString);
       NSLog(@"longitudeString %@", longitudeString);

       _latitudes = placeInfo.location.coordinate.latitude;
       _longitudes = placeInfo.location.coordinate.longitude;
    ];

    location.latitude = _latitudes;
    location.longitude = _longitudes;

    return location;

希望对你有所帮助。

谢谢。

【讨论】:

它是一个 void 方法,您正在返回一个值。如果在延迟后调用方法本身会有什么帮助? @XaviValero:对不起,我的错误是从 void 函数返回值。现在,我已经编辑好了,试试看对你有没有帮助。

以上是关于在地图视图中使用 CLGeocoder 而不是私有 API的主要内容,如果未能解决你的问题,请参考以下文章

couchdb 查询地图视图而不是减少视图

iOS - 没有互联网连接的 CLGeocoder

谷歌地图试图创建未注册类型的平台视图

如何在滚动视图中设置谷歌地图片段

CABasicAnimation 圆圈 CAShapeLayer 在地图上移动而不是缩放

使用 MKMapView 和可触摸的子视图创建视图