iOS: Array of key names in an NSDictionary where the corresponding value is @YES (or whatever you want)

I was working on a solution for storing a list of types that were being filtered by an NSFetch request from Core Data that the user gets to select. Each item had a type value that was one of 4 set strings. I decided to store an NSDictionary in NSUserDefaults with corresponding key:value pairs of (@”typeName”:@yes/@no).

What I wanted was a way to get an array of the keys from my dictionary that were enabled, so i could use:

[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"type IN %@", arrayOfTypes]];

My first thought was to use an NSPredicate on the dictionary to filter the dictionary, but while I could write one that would filter the keys down based on the name of the keys, I couldn’t come up with something that would filter the list of keys based on the value of the keys and return the key names.

My second idea ended up working, but it wasn’t as pretty as I wanted:

NSMutableArray* array = [NSMutableArray array];
for (NSString* key in [dict allKeys]) {
   if ([[dict objectForKey:key] isEqualToNumber:@YES])
     [array addObject:key];
}

I was sure there was some niceness in Objective-C that would do what I wanted in a nice package though. I asked on StackOverflow and was at first told that my solution was “the [standard] decision” by one member. I was slightly disheartened by that response but left the question open for a bit longer.

Luckily someone came in with exactly the type of solution I was looking for, using blocks:

NSArray *array = [dict keysOfEntriesPassingTest:^(id key, id obj, BOOL *stop) {
   return [obj isEqualToNumber:@YES];
}].allObjects;

Nice, clean, simple… exactly what I knew was possible but couldn’t find the function. Admittedly I don’t use blocks over other methods as often as I could, but if this doesn’t incentivize me to learn more about where I can implement them, I don’t know what will!

Feel free to comment with any improvements or alternative solutions you may have.

    • fred
    • November 13th, 2013 1:13pm

    Cool post, thanks!

  1. No trackbacks yet.