Getting NSDictionary key by index?

Sam Luther picture Sam Luther · May 14, 2014 · Viewed 27.9k times · Source

Is it possible to get a dictionary key by index?

I'm trying to use a dictionary for the datasource of a picker view and want to access it in following delegate method:

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
if (component == 0){
   return  [NSString stringWithFormat:@"%@",[myDict // how to get the key]];
}

EDIT--

myDict is something like:

Item 1

  • sub item 1
  • sub item 2

Item 2

  • sub item 1
  • sub item 2

I want to use myDict as the datasource for a picker view that has 2 sections:

section 0 = myDict keys (Item 1, Item 2)

section 1 = corresponding myDict values for selected section 0 row (sub item 1, sub item 2)

Answer

Sergey Kalinichenko picture Sergey Kalinichenko · May 14, 2014

Since NSDictionary is an unordered associative container, it has no concept of indexing. Its keys are ordered arbitrarily, and that order can change in the future.

You can get an NSArray of keys from the dictionary, and apply indexing to it:

NSArray *keys = [myDict allKeys]; // Warning: this order may change.

However, this indexing scheme would remain consistent only as long as the dictionary remains unchanged: for example, if you use NSMutableDictionary, adding an extra key may change the ordering of the existing keys. This leads to extremely hard-to-debug problems.

A better approach would be to place the items for your picker into an ordered container, such as NSArray. Create a special class for the picker items, for example

@interface MyPickerItem : NSObject
@property (readwrite, nonatomic) NSString *item1;
@property (readwrite, nonatomic) NSString *item2;
@end

create an NSArray of such MyPickerItem objects from your dictionary, order them the way you want them to appear in the picker view (say, alphabetically by item1, then by item2) and use NSArray as the data source for your picker view:

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
    MyPickerItem *p = myArray[row];
    switch (component) {
        case 0: return p.item1;
        case 1: return p.item2;
    }
    return @"<-ERROR->";
}