开发者

Changed order of objects in array without calling for it

I'm working on an application using the MapKit in iOS. I'm having trouble because at some point during my program, the order of one of the arrays switches (the array holding the coordinates), causing names of places to be paired with the wrong coordinates. I have narrowed it down to the following area:

for(CLLocation *loc in locationOutputArray)
{
    NSLog(@"Location coordinates: %f,%f",[loc coordinate].latitude,
                                         [loc coordinate].longitude);
}
NSLog(@"***************************************");
for(CLLocation *location in locationOutputArray)
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:location
                   completionHandler:^(NSArray *placemarks, NSError *error)
     {

         NSLog(@"Location coordinates:%f,%f",[location coordinate].latitude,
                                             [location coordinate].longitude);
         if(placemarks && placemarks.count > 0)
        开发者_如何学C {
             CLPlacemark *topResult = [placemarks objectAtIndex:0];

             //NSLog(@"%@",topResult);

             NSString *address = [NSString stringWithFormat:@"%@ %@, %@ %@",
                                  [topResult subThoroughfare],
                                  [topResult thoroughfare],
                                  [topResult locality],
                                  [topResult administrativeArea]];
             //NSLog(@"Address: %@", address);

             [addressOutputArray addObject:address];


             Place *place = [[Place alloc]
                             initWithName:[namesOutputArray objectAtIndex:([addressOutputArray count]-1)]
                               andAddress:address
                              andLatitude:[location coordinate].latitude 
                             andLongitude:[location coordinate].longitude
                    andStartingCoordinate:startingCoordinate];

             //NSLog(@"Distance from starting location: %f",[place distanceFromStartingPoint]);

             [finalPlaceArray addObject:place];
             [place release];
}`

The log statements for before and after the the code block respectively (separated by asterisks) are:

Location coordinates: 40.116903,-75.120631

Location coordinates: 40.129940,-75.060127

Location coordinates: 40.083996,-75.187704

Location coordinates: 40.069180,-75.126812

Location coordinates: 40.095425,-75.127777

Location coordinates: 40.095019,-75.126752

Location coordinates: 40.117596,-75.185366

Location coordinates: 40.105838,-75.212272

Location coordinates: 40.124327,-75.061865

Location coordinates: 40.010910,-75.127223

Location coordinates: 40.061088,-75.092801

Location coordinates: 40.112011,-75.165353

Location coordinates: 40.017103,-75.174498

Location coordinates: 40.139532,-75.207757

Location coordinates: 40.099432,-75.196213


Location coordinates: 40.116903,-75.120631

Location coordinates: 40.061088,-75.092801

Location coordinates: 40.010910,-75.127223

Location coordinates: 40.124327,-75.061865

Location coordinates: 40.112011,-75.165353

Location coordinates: 40.099432,-75.196213

Location coordinates: 40.139532,-75.207757

Location coordinates: 40.017103,-75.174498

Location coordinates: 40.083996,-75.187704

Location coordinates: 40.069180,-75.126812

Location coordinates: 40.129940,-75.060127

Location coordinates: 40.095019,-75.126752

Location coordinates: 40.117596,-75.185366

Location coordinates: 40.095425,-75.127777

Location coordinates: 40.105838,-75.212272

Any help would be much appreciated.


Short answer: You're printing the locations in the order that the geocoder requests complete, not the order in which they appear in the array.

Longer answer: You're making a bunch of calls to the geocoder (one call for each location in your array), and passing in a completion handler. Those calls are asynchronous, which means that you're not waiting for one to complete before you fire off the next one. When each call completes, you print its location. So, the output you're getting represents the order in which the calls are completing, not the order in which the locations appear in the original array or the order that you made the calls.

Solution: Don't rely on asynchronous calls to complete in any particular order. If you need the results to appear in some order, you'll need a way to sort them. It sounds like you're keeping place names and locations in separate arrays and trying to keep those arrays ordered the same. That's always a recipe for bugs; you'd be better off keeping everything in a single array, where each entry in the array contains both place name and location. Using a dictionary for each place may be a convenient way to achieve that.


The reason for this is because you are logging the coordinates inside of a completion handler for what is probably (definitely based on behavior) an asynchronous call. This means the handler will be called as geocoding completes so another location can complete sooner than the last. The following should give you the correct output.

for(CLLocation *location in locationOutputArray)
{
    NSLog(@"Location coordinates:%f,%f",[location coordinate].latitude,
                                        [location coordinate].longitude);
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:location
                   completionHandler:^(NSArray *placemarks, NSError *error)
     {
...

Now as for your finalPlaceArray being out of order you are going to need to implement something like clear the finalPlaceArray before your first for loop where you printed the expected results and then add [NSNull null] to each index in the loop. In your completion handler you can the replace the object with correct index.

[finalPlaceArray replaceObjectAtIndex:[locationOutputArray indexOfObject:location] withObject:place];
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜