Search code examples
objective-ccollocation

Sorting an array with each element contains an NSString and an NSNumber (double) entry


I created a NSMutableArray with two elements; the name of a city (string at index 0) and the distance (double at index 1) from my present position.

for (i=0;i<[City count];++i)
{
distanceFromMe = [Location distanceFromLocation:[cityLocation]];
[a addObject:[cityNames objectatIndex:i]];
[a addObject:@(distanceFromMe)]
[cityArray addObject:a]
}

"Chicago", 560.34

"New York", 204.3456

"Syracuse", 50.04

I would like to sort this array by ascending distances.

"Syracuse", 50.04

"New York", 204.3456

"Chicago", 560.34

I used:

[cityArray sortUsingDescriptors:@[ [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES] ]];

But I keep getting an error of an unrecognized selector sent to instance. In my reading it appears that the method does not need a key since there is only one NSNumber in the array element. I've read a number of different threads on this but none seem to apply.

Any help would be appreciated. Using xcode obj-c not swift.


Solution

  • While @JWWalker's solution works, I'd suggest modeling this a little bit differently.

    Specifically, create a class to hold the city/distance pairs:

    @interface CityDistance
    @property(copy) NSString *name;
    @property(copy) NSNumber *distance;
    @end
    
    @implementation CityDistance
    @end
    

    Store each of your city/distance pairs.

    CityDistance *cityDistance = [[CityDistance alloc] init];
    cityDistance.name = @"New York";
    cityDistance.distance = @(560.3);
    
    NSMutableArray <CityDistance *>*cities = [NSMutableArray array];
    [cities addObject: cityDistance];
    

    This allows the compiler to do more type checking, you can hang business logic off the class (i.e. maybe a -(NSNumber *)distanceFromCity:(CityDistance *)otherCity; method?), it is less fragile (oops! Forgot to add the distance to my ambiguous array!) and makes the sorting code more clear:

    [cityArray sortUsingComparator:
        ^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
            CityDistance* city1 = obj1;
            CityDistance* city2 = obj2;
            return [city1.name compare: city2.name];
        }];