Question

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)

Was it helpful?

Solution

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->";
}

OTHER TIPS

This will give you randomly ordered keys

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

No, as a dictionary doesn't have order.

You'll need to provide an array of keys, which will give you your order, in addition to the dictionary.

@interface MyClass ()
@property NSMutableArray *keysArray;     // Don't forget to allocate this in an init method
@end

- (NSString *)pickerView:(UIPickerView *)pickerView
             titleForRow:(NSInteger)row
            forComponent:(NSInteger)component
{
    if (component == 0){
        NSString *key = self.keysArray[row];
        return self.myDict[key];    // I assume you just want to return the value
    }
    ...

NSDictionary is an unordered data structure which means that accessing with an index doesn't make much sense. You probably want an NSArray instead. However, if your dictionary is using NSNumbers as keys then you would access it like this.

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
    if (component == 0) {
       return  [NSString stringWithFormat:@"%@", myDict[@(row)]];
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top