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];
精彩评论