简体   繁体   English

iPhone iOS5 CLGeocoder如何对大(200)个地址进行地理编码?

[英]iPhone iOS5 CLGeocoder how to geocode a large (200) set of addresses?

I got a large set of about 200 addresses for which I need to know their latitude and longitude. 我得到了大约200个地址,我需要知道它们的纬度和经度。 I've created a method that parses the addresses, and now I'm trying to get coordinates for these addresses using CLGeocoder . 我已经创建了一个解析地址的方法,现在我正在尝试使用CLGeocoder获取这些地址的坐标。

My current approach is to create geocoders in parallel and let them do their magic. 我目前的方法是并行创建地理编码器,让他们发挥他们的魔力。 I noticed that each one of them seems to take a separate thread. 我注意到他们每个人似乎都采取了一个单独的线程。 (so I saw up to 100 threads at one point). (所以我在一个点上看到多达100个线程)。

The problem that I'm running into is that at some point (after about 50 addresses), geocodes stop returning any place marks, and the 我遇到的问题是,在某些时候(大约50个地址之后),地理编码停止返回任何地方标记,并且

NSLog(@"Address not recognized: *%@*",[htc objectForKey:kAddressKey]);

gets called. 被叫。 Is this a limitation on a number of threads or a built-in CLGeocoder limitation? 这是对多个线程或内置CLGeocoder限制的限制吗? Could it be that I'm not cleaning up geocoders properly and need some sort of an autorelease statement(ARC)? 是不是我没有正确清理地理编码器并需要某种自动释放声明(ARC)?

-(void)geocodeArray:(NSMutableArray*)array { - (void)geocodeArray:(NSMutableArray *)array {

    NSMutableDictionary* htc = nil;
    objectsToGeocode = array.count;

    NSDictionary *htcDictionary =nil;
     for (int i = 0; i<array.count;i++) {
         htcDictionary = [array objectAtIndex:i];

        //create an updated dictionary that would hold the reverse geocoding location
        htc = [[NSMutableDictionary alloc] initWithDictionary:htcDictionary];
        NSLog(@"geocoding: %@",[htc objectForKey:kAddressKey]);

        CLGeocoder* geoCoder = [[CLGeocoder alloc] init];
        [geoCoder geocodeAddressString:[htc objectForKey:kAddressKey] completionHandler:^(NSArray *placemarks, NSError *error) {

            if(placemarks.count>0)
            {
                NSLog(@"Found placemarks for %@",[htc objectForKey:kAddressKey]);
                CLPlacemark* placemark =  [placemarks objectAtIndex:0];
                MyLocation *annotation = [[MyLocation alloc]
                                          initWithName:[htcDictionary objectForKey:kNameKey]
                                          address:[htcDictionary objectForKey:kAddressKey]
                                          coordinate:placemark.location.coordinate] ;
                annotation.faxNumber = [htc objectForKey:kFaxKey];
                annotation.phoneNumber = [htc objectForKey:kPhoneKey];
                annotation.website = [htc objectForKey:kWebsiteKey];
                annotation.type = [htc objectForKey:kFacilityTypeKey];
                [_mapView addAnnotation:annotation];  


                double placemarkToUserDistance = [self._mapView.userLocation.location distanceFromLocation:placemark.location] ;
                //convert distance to miles
                placemarkToUserDistance =placemarkToUserDistance/ 1000/ kKilometersPerMile;

                [htc setObject:[NSNumber numberWithDouble:placemarkToUserDistance] forKey:kDistanceToUserKey];
                [htc setObject:[NSNumber numberWithDouble:placemark.location.coordinate.latitude] forKey:kLatitudeKey];
                 [htc setObject:[NSNumber numberWithDouble:placemark.location.coordinate.longitude] forKey:kLongitudeKey];
                NSAssert([htc objectForKey:kLatitudeKey]!=nil,@"kLatitudeKey is not saved!");
                NSAssert([htc objectForKey:kLongitudeKey]!=nil,@"kLongitudeKey is not saved!");

            }else {
                NSLog(@"Address not recognized: *%@*",[htc objectForKey:kAddressKey]);
            }


            [self.dataSource addObject:htc];

            if(++geocodingCount >=objectsToGeocode){
                NSLog(@"%@",self.dataSource);
                    [self saveGeocoding];

            }

        } ];


        //        [temp addObject:htcDictionary];
    }

}

To test if this is a threading issue, I created this method, which splits my large dataset into 5 arrays, and attempts to geocode them in chunks. 为了测试这是否是一个线程问题,我创建了这个方法,它将我的大数据集拆分为5个数组,并尝试将它们分块进行地理编码。 I noticed that the first request passes, as well as a part of a second one. 我注意到第一个请求通过,第二个请求通过。 But once the magic number of (~50) is reached, the geocoding stops. 但是一旦达到(~50)的幻数,地理编码就会停止。

Any ideas of what may be happening? 对可能发生的事情的任何想法? Is this an Apple imposed limit on the number of geocoding operations? 这是Apple对地理编码操作数量的限制吗? Should I increase the delay between requests or try to run the app 5 separate times and piece together the results by hand? 我应该增加请求之间的延迟还是尝试分别运行应用程序5并手动拼凑结果?

-(void)geocodeDatasource
{

        //I'm trying to build a file with coordinates of addresses and include it with the app
        geocodingCount = 0;
        self.dataSource = [[NSMutableArray alloc] initWithCapacity:self.arrayForGeocodingInitialJSON.count+5];
        haveToEmailInitialResults = YES;


    //attempt to geocode in batches

     float numberOfArrays = 5.0;
    NSMutableArray* array1 = [[NSMutableArray alloc] initWithCapacity:arrayForGeocodingInitialJSON.count/numberOfArrays];
    NSMutableArray* array2 = [[NSMutableArray alloc] initWithCapacity:arrayForGeocodingInitialJSON.count/numberOfArrays];
    NSMutableArray* array3 = [[NSMutableArray alloc] initWithCapacity:arrayForGeocodingInitialJSON.count/numberOfArrays];
    NSMutableArray* array4 = [[NSMutableArray alloc] initWithCapacity:arrayForGeocodingInitialJSON.count/numberOfArrays];
    NSMutableArray* array5 = [[NSMutableArray alloc] initWithCapacity:arrayForGeocodingInitialJSON.count/numberOfArrays];

    for(int i = 0 ;i<arrayForGeocodingInitialJSON.count;i++)
    {
        id object = [arrayForGeocodingInitialJSON objectAtIndex:i];
        if(i<arrayForGeocodingInitialJSON.count*(1/numberOfArrays))
        {
            [array1 addObject:object];
        }else if(i>=arrayForGeocodingInitialJSON.count/numberOfArrays && i<arrayForGeocodingInitialJSON.count*(2/numberOfArrays))
        {
            [array2 addObject:object];
        }else if(i>=arrayForGeocodingInitialJSON.count*(2/numberOfArrays) && i<arrayForGeocodingInitialJSON.count*(3/numberOfArrays))
        {
            [array3 addObject:object];
        }else if(i>=arrayForGeocodingInitialJSON.count*(3/numberOfArrays) && i<arrayForGeocodingInitialJSON.count*(4/numberOfArrays))
        {
            [array4 addObject:object];
        }else if(i>=arrayForGeocodingInitialJSON.count*(4/numberOfArrays) && i<arrayForGeocodingInitialJSON.count)
        {
            [array5 addObject:object];
        }



    }

    //simple delays eliminate the need for extra variables and notifications
        [self geocodeArray:array2];

        [self performSelector:@selector(geocodeArray:) withObject:array1 afterDelay:15];
        [self performSelector:@selector(geocodeArray:) withObject:array3 afterDelay:30];
        [self performSelector:@selector(geocodeArray:) withObject:array4 afterDelay:45];
        [self performSelector:@selector(geocodeArray:) withObject:array5 afterDelay:45];
}

Thank you! 谢谢!

You can't immediately geocode large sets. 您无法立即对大型地理位置进行地理编码。 iOS throttles you. iOS限制了你。 I have seen that iOS limits you to 50 geocodes at a time, with the "time" factor being an unknown. 我已经看到iOS一次限制你50个地理编码,“时间”因素是未知的。

I've had a similar problem, but as I needed only to present the geocoding data in a sequence to the user that takes time, I queued all my geocodings. 我遇到了类似的问题,但由于我只需要将序列中的地理编码数据呈现给需要时间的用户,我将所有的地理编码排队。

Effectively, I geocode a chunk of 25 - display the results to the user 1 at a time at about an interval of a half second between each. 实际上,我对25块进行了地理编码 - 将结果一次显示给用户1,每次间隔半秒。 When I have fewer than 4 left to display, I will geocode the next 25. This continues until everything is geocoded (or in my case, indefinitely). 当我剩下少于4个显示时,我将对下一个25进行地理编码。这将一直持续到所有地理编码(或者在我的情况下,无限期)。

If you need to have everything geocoded at once, you'll need to chain your geocodings together with delays between each chunk and show some sort of busy indicator until you are done. 如果您需要同时对所有地理编码进行地理编码,则需要将您的地理编码链接在一起,并在每个块之间延迟并显示某种忙碌指示符,直到完成为止。 Which could be some time with large sets of geocodings. 大型地理编码可能需要一段时间。

The answer is you are violating the TOS for Apple's geocoder. 答案是你违反了苹果地理编码器的服务条款。

From the CLGeocoder documentation. CLGeocoder文档。

Applications should be conscious of how they use geocoding. 应用程序应该意识到它们如何使用地理编码。 Here are some rules of thumb for using this class effectively: 以下是有效使用此类的一些经验法则:

Send at most one geocoding request for any one user action. 为任何一个用户操作最多发送一个地理编码请求。 If the user performs multiple actions that involve geocoding the same location, reuse the results from the initial geocoding request instead of starting individual requests for each action. 如果用户执行涉及对同一位置进行地理编码的多个操作,请重复使用初始地理编码请求的结果,而不是为每个操作启动单个请求。 When you want to update the user's current location automatically (such as when the user is moving), issue new geocoding requests only when the user has moved a significant distance and after a reasonable amount of time has passed. 当您想要自动更新用户的当前位置时(例如当用户移动时),仅在用户移动了相当长的距离并经过一段合理的时间后才发出新的地理编码请求。 For example, in a typical situation, you should not send more than one geocoding request per minute. 例如,在典型情况下,您不应每分钟发送多个地理编码请求。 Do not start a geocoding request at a time when the user will not see the results immediately. 当用户不立即看到结果时,请勿启动地理编码请求。 For example, do not start a request if your application is inactive or in the background. 例如,如果您的应用程序处于非活动状态或在后台运行,请不要启动请求。

Apple would be well within their rights to stop providing responses, cut off your app entirely, or even revoke your developer account. Apple完全有权停止提供回复,完全切断您的应用,甚至撤销您的开发者帐户。

If you need to process such a large number of address quickly, then you should look into getting a service like Factual for Points of Interest or Data Science Toolkit for postal addresses and geographic regions. 如果您需要快速处理如此大量的地址,那么您应该考虑获得像Factual for Interest of Interest或Data Science Toolkit这样的服务,用于邮政地址和地理区域。


Update 更新

Here is the API docs for Places API - Resolve , which is Factual's places geocoder. 以下是Places API - Resolve的API文档,它是Factual的地方编码器。


Update 2 更新2

Here is the API for Street Address to Coordinates , which is Data Science Toolkit's location geocoder. 以下是街道地址到坐标的API,它是Data Science Toolkit的位置地理编码器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM