NSDictionary
Objective-C
key-value
programming
duplicate

NSDictionary Key For Value/Object?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

NSDictionary is optimized for key-to-value lookup, not reverse lookup from value to key. When you need a key for a given object, you either scan entries or maintain an additional reverse index. The right choice depends on data size, update frequency, and whether duplicate values are possible.

Direct Reverse Lookup by Enumeration

For occasional lookups on small dictionaries, iterate through keys and compare values.

objective-c
1NSDictionary *map = @{
2    @"apple" : @1,
3    @"banana" : @2,
4    @"orange" : @1
5};
6
7id targetValue = @2;
8id foundKey = nil;
9
10for (id key in map) {
11    if ([map[key] isEqual:targetValue]) {
12        foundKey = key;
13        break;
14    }
15}
16
17NSLog(@"Found key: %@", foundKey);

This is simple and readable, but complexity is linear in dictionary size.

Handling Duplicate Values Correctly

Values in NSDictionary are not guaranteed unique. If several keys map to the same value, returning one key may not be enough.

objective-c
1id targetValue = @1;
2NSMutableArray *keys = [NSMutableArray array];
3
4for (id key in map) {
5    if ([map[key] isEqual:targetValue]) {
6        [keys addObject:key];
7    }
8}
9
10NSLog(@"All keys for value %@: %@", targetValue, keys);

Decide early whether your API should return first match or all matches.

Building a Reverse Index for Repeated Queries

If reverse lookup happens frequently, build a secondary map once.

objective-c
1NSDictionary *forward = @{
2    @"apple" : @1,
3    @"banana" : @2,
4    @"orange" : @1
5};
6
7NSMutableDictionary<id, NSMutableArray *> *reverse = [NSMutableDictionary dictionary];
8
9[forward enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
10    if (!reverse[obj]) {
11        reverse[obj] = [NSMutableArray array];
12    }
13    [reverse[obj] addObject:key];
14}];
15
16NSLog(@"Keys for value 1: %@", reverse[@1]);

This shifts work from query time to build time and is usually better for performance when lookups are frequent.

Swift Equivalent Pattern

In Swift, the same concept is concise and type-safe.

swift
1let forward: [String: Int] = ["apple": 1, "banana": 2, "orange": 1]
2var reverse: [Int: [String]] = [:]
3
4for (k, v) in forward {
5    reverse[v, default: []].append(k)
6}
7
8print(reverse[1] ?? [])

Use this approach when writing modern iOS codebases that mix Objective-C and Swift modules.

Equality and Hashing Considerations

Reverse lookup correctness depends on value equality semantics. For object values, isEqual: must reflect logical equality, and hash behavior should be consistent.

If your value objects are mutable, reverse indexes can become stale after mutation. Prefer immutable value objects for keys and indexed values where possible.

Designing API Behavior

For maintainable code, make reverse lookup API explicit:

  • keyForValue: returns first key or nil.
  • keysForValue: returns all matching keys.

Document ordering expectations. Dictionary iteration order is not a sorting guarantee.

Choosing Between Scan and Index

For one-off lookups, scanning is often perfectly fine and keeps code simple. For repeated lookups inside loops or request handlers, building a reverse index usually pays off quickly.

A practical rule is to start with linear scan, then switch to reverse index when profiling shows lookup cost is meaningful. This prevents premature optimization while still giving a clear migration path as data grows.

If ordering matters for returned keys, sort the results explicitly before returning. Dictionary traversal order should not be treated as business ordering unless your application contract defines it.

Common Pitfalls

A common pitfall is assuming one-to-one mapping between keys and values. Reverse lookup logic breaks when duplicates appear unless this is handled explicitly.

Another issue is using pointer equality instead of value equality for object comparison. Use isEqual: to compare semantic value.

Developers also rebuild reverse indexes repeatedly inside loops. Build once and reuse if the source dictionary is stable.

Finally, mutating data after reverse index creation without refreshing the index leads to incorrect results. Keep update paths synchronized.

Summary

  • NSDictionary supports fast key-to-value lookup, not value-to-key lookup.
  • Enumerate for occasional reverse lookups on small data.
  • Build a reverse index for repeated queries.
  • Handle duplicate values by returning multiple keys when needed.
  • Ensure equality semantics and index refresh behavior are clearly defined.

Course illustration
Course illustration

All Rights Reserved.