我正在获取所有图像的GPS信息,并将它们存储在字典中。我会传递lat&此词典中的长值到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];
});
}
}
}
答案 0 :(得分:2)
简短的回答是你不能让它同步。
您要做的是将继续执行下一个对象的代码移动到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
}
}
}
当然,你不能依赖于这样做来做任何其他事情,除非你在反向编码最后一个对象时可能会踢掉一些东西。
这种异步编程可以让你疯狂。
答案 1 :(得分:1)
另一种方法是将同步请求发送到以下URL,该URL以XML格式返回反向地理编码结果。您可以稍后解析它,转换为JSON或其他。最好的部分:1)你强制同步反向地理编码的整个过程
2)对于你可以做出的最大请求没有限制(我认为在调用reverseGeocodeLocation
处理程序时它是50 / min)。如果超出,则会出现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);
}