Objective-C
NSDictionary
Key Order
iOS Development
Data Structures

NSDictionary with ordered keys

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

NSDictionary in Objective-C (and Dictionary in Swift) does not guarantee key order. If you need ordered keys, use a separate NSArray to track key order alongside the dictionary, use NSOrderedSet for unique ordered keys, or create a custom ordered dictionary wrapper. In Swift, third-party libraries like OrderedDictionary from the Swift Collections package provide this functionality directly.

NSDictionary Is Unordered

objc
1NSDictionary *dict = @{
2    @"banana": @2,
3    @"apple": @1,
4    @"cherry": @3
5};
6
7// Key order is NOT guaranteed
8for (NSString *key in dict) {
9    NSLog(@"%@: %@", key, dict[key]);
10}
11// May print in any order — not necessarily insertion order

Solution 1: Separate Key Array

The simplest approach — maintain an array of keys in the desired order:

objc
1NSArray *orderedKeys = @[@"apple", @"banana", @"cherry"];
2NSDictionary *dict = @{
3    @"banana": @2,
4    @"apple": @1,
5    @"cherry": @3
6};
7
8// Iterate in order
9for (NSString *key in orderedKeys) {
10    NSLog(@"%@: %@", key, dict[key]);
11}
12// apple: 1
13// banana: 2
14// cherry: 3

For mutable dictionaries:

objc
1NSMutableArray *orderedKeys = [NSMutableArray array];
2NSMutableDictionary *dict = [NSMutableDictionary dictionary];
3
4// Add in order
5[orderedKeys addObject:@"first"];
6dict[@"first"] = @1;
7
8[orderedKeys addObject:@"second"];
9dict[@"second"] = @2;
10
11// Remove
12[orderedKeys removeObject:@"first"];
13[dict removeObjectForKey:@"first"];

Solution 2: Custom Ordered Dictionary Class

objc
1@interface OrderedDictionary<KeyType, ObjectType> : NSObject
2
3- (void)setObject:(ObjectType)object forKey:(KeyType<NSCopying>)key;
4- (ObjectType)objectForKey:(KeyType)key;
5- (void)removeObjectForKey:(KeyType)key;
6- (NSArray<KeyType> *)allKeys;
7- (NSUInteger)count;
8- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(KeyType key, ObjectType obj, BOOL *stop))block;
9
10@end
11
12@implementation OrderedDictionary {
13    NSMutableArray *_keys;
14    NSMutableDictionary *_dict;
15}
16
17- (instancetype)init {
18    self = [super init];
19    if (self) {
20        _keys = [NSMutableArray array];
21        _dict = [NSMutableDictionary dictionary];
22    }
23    return self;
24}
25
26- (void)setObject:(id)object forKey:(id<NSCopying>)key {
27    if (![_dict objectForKey:key]) {
28        [_keys addObject:key];
29    }
30    [_dict setObject:object forKey:key];
31}
32
33- (id)objectForKey:(id)key {
34    return [_dict objectForKey:key];
35}
36
37- (void)removeObjectForKey:(id)key {
38    [_dict removeObjectForKey:key];
39    [_keys removeObject:key];
40}
41
42- (NSArray *)allKeys {
43    return [_keys copy];
44}
45
46- (NSUInteger)count {
47    return [_keys count];
48}
49
50- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block {
51    [_keys enumerateObjectsUsingBlock:^(id key, NSUInteger idx, BOOL *stop) {
52        block(key, self->_dict[key], stop);
53    }];
54}
55
56@end

Usage:

objc
1OrderedDictionary *od = [[OrderedDictionary alloc] init];
2[od setObject:@1 forKey:@"apple"];
3[od setObject:@2 forKey:@"banana"];
4[od setObject:@3 forKey:@"cherry"];
5
6[od enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *value, BOOL *stop) {
7    NSLog(@"%@: %@", key, value);
8}];
9// apple: 1, banana: 2, cherry: 3 (insertion order guaranteed)

Solution 3: Sorted Keys

If you want alphabetical order (not insertion order):

objc
1NSDictionary *dict = @{@"banana": @2, @"apple": @1, @"cherry": @3};
2
3NSArray *sortedKeys = [[dict allKeys] sortedArrayUsingSelector:@selector(compare:)];
4for (NSString *key in sortedKeys) {
5    NSLog(@"%@: %@", key, dict[key]);
6}
7// apple: 1, banana: 2, cherry: 3
8
9// Custom sort
10NSArray *customSorted = [[dict allKeys] sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
11    return [dict[a] compare:dict[b]]; // Sort by value
12}];

Swift: OrderedDictionary (Swift Collections)

swift
1// Add to Package.swift:
2// .package(url: "https://github.com/apple/swift-collections", from: "1.0.0")
3
4import OrderedCollections
5
6var ordered = OrderedDictionary<String, Int>()
7ordered["apple"] = 1
8ordered["banana"] = 2
9ordered["cherry"] = 3
10
11// Iteration preserves insertion order
12for (key, value) in ordered {
13    print("\(key): \(value)")
14}
15// apple: 1, banana: 2, cherry: 3
16
17// Access by index
18print(ordered.elements[0])  // (key: "apple", value: 1)

Swift: Manual Approach

swift
1struct OrderedDict<Key: Hashable, Value> {
2    private var keys: [Key] = []
3    private var dict: [Key: Value] = [:]
4
5    mutating func set(_ value: Value, forKey key: Key) {
6        if dict[key] == nil {
7            keys.append(key)
8        }
9        dict[key] = value
10    }
11
12    func get(_ key: Key) -> Value? {
13        return dict[key]
14    }
15
16    var orderedKeys: [Key] { keys }
17    var orderedValues: [Value] { keys.compactMap { dict[$0] } }
18}

Common Pitfalls

  • Assuming NSDictionary preserves insertion order: NSDictionary and Swift Dictionary do not guarantee any key ordering. Even if keys appear ordered in small tests, the order can change with different data sizes or runtime conditions.
  • Using allKeys and expecting consistent order: [dict allKeys] returns keys in an arbitrary order that may differ between calls (though it is typically stable within a single run). Never rely on it for ordered iteration.
  • Not keeping the key array in sync: When using a separate NSMutableArray for ordered keys, forgetting to add/remove keys when modifying the dictionary causes inconsistencies. Always wrap both operations in a helper method.
  • Performance of linear search in key array: [NSMutableArray removeObject:] and containsObject: are O(n). For large dictionaries (1000+ keys), this becomes slow. Use NSMutableOrderedSet instead of NSMutableArray for O(1) lookups.
  • JSON serialization losing order: NSDictionary serialized to JSON via NSJSONSerialization does not preserve key order. If key order matters for the JSON output, serialize manually or use an ordered JSON library.

Summary

  • NSDictionary and Swift Dictionary are unordered — key iteration order is not guaranteed
  • Maintain a separate NSArray/Array of keys alongside the dictionary for insertion order
  • Use the Swift Collections package (OrderedDictionary) for a production-ready ordered dictionary
  • Sort keys with sortedArrayUsingSelector: or sorted() for alphabetical order
  • Wrap key array + dictionary operations in a custom class to keep them synchronized
  • For JSON output with ordered keys, use a specialized serialization approach

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.