【问题标题】:Reverse geocoding from given coordinates (not current location, but manually provided)从给定坐标反向地理编码(不是当前位置,而是手动提供)
【发布时间】:2014-02-09 20:26:48
【问题描述】:

我正在获取我所有图像的 GPS 信息,并将它们存储在字典中。我会将此字典中的 lat & long 值传递给 reverseGeocodeLocation 函数调用并将结果存储在我的数据库中。

这里的问题是这个函数是一个异步调用&我需要同步整个过程才能让我的记录插入到表中。

例如:我的数组读取以下坐标:32.77003,96.87532。它现在调用reverseGeocodeLocation 函数,将这些坐标作为CLLocation 对象传递。现在,在这个异步函数将地理编码位置名称返回给我之前,下一个带有新坐标集的请求被发送到reverseGeocodeLocation 函数。这会导致将记录插入数据库的不一致。

有没有办法让整个任务同步?
即让我的 for 循环等到 reverseGeocodeLocation 返回一个值,然后转到下一条记录进行地理编码?

我的一些代码在这里:

for (int imgIdx=0; imgIdx<[imageMetaMutArray count]; imgIdx++)
{
    NSDictionary *localGpsDict = [[NSDictionary alloc]initWithDictionary: [imageMetaMutArray objectAtIndex:imgIdx]];
    imgLatLoc=[localGpsDict valueForKey:@"Latitude"];
    imgLongLoc=[localGpsDict valueForKey:@"Longitude"];
    dateStamp=[localGpsDict valueForKey:@"DateStamp"];
    timeStamp=[localGpsDict valueForKey:@"TimeStamp"];

    if(imgLatLoc && imgLongLoc && dateStamp && timeStamp)
    {
        CLGeocoder *geoCoder=[[CLGeocoder alloc]init];
        CLLocation *currentLocation=[[CLLocation alloc]initWithLatitude:[imgLatLoc doubleValue] longitude:[imgLongLoc doubleValue]];

        [geoCoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placeMarks, NSError *err){
        if(err)
        {
            NSLog(@"Reverse geo-coding failed because: %@",err);
            return;
        }


        if(placeMarks && placeMarks.count>0)
        {
            CLPlacemark *placeMarkers=placeMarks[0];
            NSDictionary *locationDictionary=placeMarkers.addressDictionary;

            NSString *country=[locationDictionary objectForKey:(NSString *)kABPersonAddressCountryKey];
            NSString *city=[locationDictionary objectForKey:(NSString *)kABPersonAddressCityKey];
            NSString *state=[locationDictionary objectForKey:(NSString *)kABPersonAddressStateKey];

            NSLog(@"logged in from:");

                if(city)
                {
                    NSLog(@"city: %@",city);
                    locName = [[NSString alloc]initWithString:city];
                    if(state)
                    {
                        NSLog(@"state: %@",state);
                        locName=[locName stringByAppendingString:@","];
                        locName=[locName stringByAppendingString:state];
                    }
                    if(country)
                    {
                        NSLog(@"country: %@",country);
                        locName=[locName stringByAppendingString:@","];
                        locName=[locName stringByAppendingString:country];
                    }
                }
                else
                {
                        if(state)
                        {
                            NSLog(@"state: %@",state);
                            locName = [[NSString alloc]initWithString:state];
                            if(country)
                            {
                                NSLog(@"country: %@",country);
                                locName=[locName stringByAppendingString:@","];
                                locName=[locName stringByAppendingString:country];
                            }
                        }
                        else
                        {
                            NSLog(@"country: %@",country);
                            locName = [[NSString alloc]initWithString:country];
                        }
                    }
                }
                else
                {
                    NSLog(@"Placemark Error code:: %lu\n%@",(unsigned long)placeMarks.count,placeMarks);
                }

                [locName retain];
                NSLog(@"location decoded is: %@",locName);
                /*Call for Insert into Images table*/
               [self insertDataImgTbl:locName];
          });
      }
   }
}

【问题讨论】:

  • 上面的变量imageMetaMutArray将图像的GPS信息数组保存为NSDictionary

标签: ios core-location reverse-geocoding clgeocoder


【解决方案1】:

简短的回答是你不能让它同步。

您想要做的是将继续到下一个对象的代码移动到 reverseGeocodeLocation 的完成块中,因为这是您可以提交另一个 reverseGeocodeLocation 请求的最快速度。让我看看我是否可以在这里制作一些伪代码......(也就是说,我没有编译它,所以它可能不完全正确......)

    // in place of the original for loop:
    [self reverseGeocodeForIndex:0];


// Doing the reverse geocode is in a method so you can easily call it from within the completion block.
// Maybe your parameter is not the imgIdx value but is instead some object -- I'm just hacking your posted code
// The point is that your completion block has to be able to tell when
// it is done and how to go on to the next object when it is not done.
(void) reverseGeocodeForIndex:(int) imgIdx {
    NSDictionary *localGpsDict = [[NSDictionary alloc]initWithDictionary: [imageMetaMutArray objectAtIndex:imgIdx]];
    imgLatLoc=[localGpsDict valueForKey:@"Latitude"];
    imgLongLoc=[localGpsDict valueForKey:@"Longitude"];
    dateStamp=[localGpsDict valueForKey:@"DateStamp"];
    timeStamp=[localGpsDict valueForKey:@"TimeStamp"];

    if(imgLatLoc && imgLongLoc && dateStamp && timeStamp)
    {
        CLGeocoder *geoCoder=[[CLGeocoder alloc]init];
        CLLocation *currentLocation=[[CLLocation alloc]initWithLatitude:[imgLatLoc doubleValue] longitude:[imgLongLoc doubleValue]];

        [geoCoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placeMarks, NSError *err){
        // completion block
            if(err)
            {
                 // error stuff
            }

            if(placeMarks && placeMarks.count>0)
            {
                 // what happens when you get some data
            }

            // now see if we are done and if not do the next object
            if (imgIdx<[imageMetaMutArray count])
            {
                [self reverseGeocodeForIndex:imgIdx+1];
            } else {
                // Everything is done maybe you want to start something else
            }
        }];
    } else {
        // Since you might not reverseGeocode an object you need an else case
        // here to move on to the next object.
        // Maybe you could be more clever and not duplicate this code.
        if (imgIdx<[imageMetaMutArray count])
        {
            [self reverseGeocodeForIndex:imgIdx+1];
        } else {
            // Everything is done maybe you want to start something else
        }
    }
}

而且,当然,除了对最后一个对象进行反向地理编码时,您可能会启动某些东西,否则您不能依赖此操作来做任何其他事情。

这种异步编程会让你发疯。

【讨论】:

  • 谢谢查理!我认为这种方法可能适用于删除 for 循环。我自己曾考虑过使用 while 循环,但递归函数调用也可以完成这项工作。同时,我为整个问题管理了一个完全不同的解决方法。本质上,reverseGeocodeLocation 将异步 NSURLConnection 请求发送到服务器以获取反向地理编码数据。我自己完成整个过程,但使用同步调用。它工作得很好,我也不受最大调用次数(50)的限制,否则它会给出kCLErrorDomain 代码 2 错误。
【解决方案2】:

另一种方法是向以下 URL 发出同步请求,该 URL 以 XML 格式返回反向地理编码结果。您可以稍后对其进行解析、转换为 JSON 或其他任何内容。最好的部分:1)您正在强制同步反向地理编码的整个过程 2) 您可以发出的最大请求数没有限制(我认为在调用reverseGeocodeLocation 处理程序的情况下它是50/分钟)。如果超过,您将收到 kCLErrorDomain 代码 2 错误。所以我们通过下面的方法来避免所有这些。一些适用于我的示例代码:

-(NSString *)giveMeLocName: (double)gpsLat :(double)gpsLong
{
NSString *finalLocation=[[NSString alloc]init];
//Below is URL we need to send request
NSString *reverseGeoCodeLoc = [NSString
                                 stringWithFormat:@"http://nominatim.openstreetmap.org/reverse?format=xml&zoom=18&addressdetails=1&accept-language=en&lat=%lg&lon=%lg",gpsLat,gpsLong];

NSURL *myLocUrl = [NSURL URLWithString:reverseGeoCodeLoc];
ASIHTTPRequest *myLocRequest = [ASIHTTPRequest requestWithURL:myLocUrl];
[myLocRequest setDidFinishSelector:@selector(reverseGeoCodeImg:)];

[myLocRequest setDelegate:self];
[myLocRequest startSynchronous];
NSLog(@"waiting for location info..");
//Do stuff after receiving results here
}

//This block receives HTTP response as XML(containing reverse geo-coded info. I parse this to JSON using XMLReader class(downloadable)
-(void)reverseGeoCodeImg:(ASIHTTPRequest *)request
{
/*Allocations*/
locDict=[[NSDictionary alloc]init];
revGeoCodePart=[[NSDictionary alloc]init];
addressParts=[[NSDictionary alloc]init];
cityName=[[NSString alloc]init];
stateName=[[NSString alloc]init];
countryName=[[NSString alloc]init];

NSLog(@"starting reverse geo-code!!");
NSString *responseString = [request responseString];

NSError *parseError = nil;
locDict=[XMLReader dictionaryForXMLString:responseString error:&parseError];
[locDict retain];
revGeoCodePart=[locDict objectForKey:@"reversegeocode"];
[revGeoCodePart retain];
addressParts=[revGeoCodePart objectForKey:@"addressparts"];
[addressParts retain];

cityName=[[addressParts objectForKey:@"city"] objectForKey:@"text"];
[cityName retain];
stateName=[[addressParts objectForKey:@"state"]objectForKey:@"text"];
[stateName retain];
countryName=[[addressParts objectForKey:@"country"]objectForKey:@"text"];
[countryName retain];

NSLog(@"city: %@\nstate: %@\ncountry: %@",cityName,stateName,countryName);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-04
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    相关资源
    最近更新 更多