2011-10-03 4 views
1

아래 코드를 사용하여 지오 코딩을 통해 위치 정보를 가져온 다음 Google지도보기에지도 핀을 추가합니다. 이 코드는 For 루프를 사용하여 데이터베이스의 각 위치를 순환합니다. 문제는 코드가 실행될 때 장소의 약 50 %에 대한 위치 정보를 반환하지 못한다는 것입니다. 이러한 실패한 항목은 아래 코드에 따라 failedLoad 배열에 저장됩니다.Google 지오 코딩이있는 For 루프 - 높은 오류율 - iPhone

누구에게 제안 할 수 있습니까? 또한 이러한 실패한 항목은 "failedLoad"배열에 저장되므로 누락 된 핀을로드 할 때이 배열을 사용할 수 있습니까?

편집

실패한 항목은 내가 너무 빨리 항목을 제출하고 있음을 의미 620 오류에 기인한다. 코드에 지연을 어떻게 추가 할 수 있습니까?

감사합니다. 대신 for 루프를 사용하여 동시에 모든 요청을 보낼의

-(void)displayPlaces { 


for (PlaceObject *info in mapLocations) { 

     // GET ANNOTATION INFOS 
     NSString * addressOne = info.addressOne; 
     NSString * name = info.name; 
     NSString * postCode = info.postCode; 

     NSString * addressTwo = [addressOne stringByAppendingString:@",London,"]; 
     NSString * address = [addressTwo stringByAppendingString:postCode]; 

     NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 
     NSURL* url = [NSURL URLWithString:urlString]; 
     NSURLRequest* req = [NSURLRequest requestWithURL:url]; 

     OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req]; 
     [loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) { 
      NSString* locationString = loader.receivedString; 
      NSArray *listItems = [locationString componentsSeparatedByString:@","]; 

     double latitude = 0.0; 
     double longitude = 0.0; 

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

     } 

     else { 

      NSLog(@"Error %@",name); 
      [failedLoad addObject : info]; 

     } 


     CLLocationCoordinate2D coordinate; 
     coordinate.latitude = latitude; 
     coordinate.longitude = longitude; 
     MyLocation *annotation = [[[MyLocation alloc] initWithName:name address:address coordinate:coordinate] autorelease]; 

     [mapViewLink addAnnotation:annotation]; 

     } errorHandler:^(NSError *error) { 
      NSLog(@"Error while downloading %@: %@",url,error); 
     }]; 

} 


} 
+0

Google API에는 다양한 쿼리 속도 제한이 있습니다 (예 : 초당 최대 10 개의 요청 API를 사용할 계획이라면이 모든 것을 RTFM해야합니다. –

+1

위치를로드하지 못하면 반환 된 문자열을 기록하지 않는 것이 좋습니다. 왜 실패하는지 즉시 즉시 알 수 있습니다. – JeremyP

+0

감사합니다. 제가 이해하는 620 오류는 제가 제출하는 비율 때문입니다. 코드에 어떻게 지연을 넣을 수 있습니까? – GuybrushThreepwood

답변

2

, 당신은 아마 그들에게 하나씩 보내야합니다 (5하거나 5?)

가 여기에 그것을 할 수있는 한 방법입니다 (I 일부 오타가있을 수 있으므로 가서 방금 입력, 실제 코드에서 테스트되지 않음) : 물론

// In the instance variables, have: 
@property(retain) NSMutableSet* mapLocationsToGeocode; 

// When you want to decode, use: 
self.mapLocationsToGeocode = [NSMutableSet setWitharray:mapLocations]; 
// (Or add to the existing NSSet if you have one and add Places using multple passes) 
[self popLocationAndGeocode]; 

-(void)popLocationAndGeocode 
{ 
    // Pop any location from the set 
    PlaceObject* onePlace = [mapLocationsToGeocode anyObject]; 

    // Build the URL given the PlaceObject 
    NSString* address = [NSString stringWithFormat:@"%@,London,%@",info.addressOne,info.postCode]; 
    NSString* name = info.name; 

    NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@&output=csv", [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 
    NSURLRequest* req = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]; 

    // Remove it so it won't be poped again 
    [mapLocationsToGeocode removeObject:onePlace]; 

    // Send the request here to decode the PlaceObject 
    OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req]; 
    [loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) { 
    NSString* locationString = loader.receivedString; 
    NSArray* listItems = [locationString componentsSeparatedByString:@","]; 
    ... 

    if([listItems count] >= 4 && [[listItems objectAtIndex:0] isEqualToString:@"200"]) { 
     // Process with latitude and longitude, add your MKAnnotation, etc 
    } else { 
     NSLog(@"Error %@",name); 
     [failedPlaces addObject:onePlace]; 
    } 
    ... 

    // Schedule the next decoding request (1) 
    if ([mapLocationsToGeocode count]) [self performSelector:@selector(popLocationAndGeocode) withObject:nil afterDelay:0.1]; 
    } errorHandler:^(NSError *error) { 
     NSLog(@"Error while downloading %@: %@",url,error); 
     [failedPlaces addObject:onePlace]; 

     // Schedule the next decoding request anyway (1) 
     if ([mapLocationsToGeocode count]) [self performSelector:@selector(popLocationAndGeocode) withObject:nil afterDelay:0.1]; 
    }]; 

    // Schedule the next decoding request (2) -- solution 2 
    // if ([mapLocationsToGeocode count]) [self performSelector:@selector(popLocationAndGeocode) withObject:nil afterDelay:1.0]; // wait one sec before sending next request 
} 

가 전무로 다시 속성을 설정하는 것을 잊지 해달라고 할 때 (또는 dealloc에서) 자료에 기억.

(1)의 경우 완료 및 오류 블록 모두에서 performSelector:withObject:afterDelay을 호출하므로 첫 번째 요청이 완료되면 다음 요청/디코딩 프로세스가 호출됩니다. 이렇게하면 요청이 다소 직렬화됩니다. 경우

(2), 내가 바로 startRequestWithCompletion:... 방법 후 performSelector:withObject:afterDelay를 호출 (/ 비활성화 댓글을 달았습니다), 그래서 다음 중 하나를 팝업하는 최초의 요청이 끝날 때까지 기다리지 않습니다. 당신이이 유일한 해결책이 아니라는 GoogleAPI의 속도 제한을


주에 도달하지 않을 것이다 많은 다른 가능성이되도록하지만 당신은 충분히 (희망) 기다립니다. 하나는 NSOperationQueue을 사용하여 요청을 큐에 하나씩 큐에 넣고 종속성을 추가하거나 GCD 직렬 큐에서 요청을 보내는 프로세스를 예약합니다 (예, 실제로 GCD를 사용하지 말라고 말한 것을 알고 있습니다) 귀하의 요청을 보내지 만 GCD + 동기 요청을 여전히 사용하지 마십시오. 그러나 GCD를 사용하여 [OHURLLoader startRequestWithCompletion:...]을 주 스레드에서 차례로 호출하는 블록을 대기열에 넣을 수 있으며 요청 자체는 여전히 주 스레드에서 실행됩니다. RunLoop)

+0

감사합니다. 잘 작동하는 것 같습니다. 그러나 핀 추가가 ​​끝나면 앱이 다운됩니다. mapLocationsToGeocode 배열이 비어있는 경우 선택기/타이머를 중지하려면 어떻게합니까? – GuybrushThreepwood

+0

Ok로 고정 : [self performSelector : @selector (popLocationAndGeocode) withObject : nil afterDelay : 0.15]; int x = [mapLocationsToGeocode 개수]; if (x <= 1) { [NSObject cancelPreviousPerformRequestsWithTarget : 셀렉터 : @selector (popLocationAndGeocode) object : nil]; } – GuybrushThreepwood

+0

오, 예, 중지 조건을 잊어 버렸습니다.) "performSelector"요청을 예약 한 다음 바로 취소하는 대신, 일정을 지정하지 않아야합니다. 즉, if ([mapLocationsToGeocode count]) [self performSelector : ... withObject : nil afterDelay : ...] ' – AliSoftware