I have an NSDictionary (stored in a plist) that I'm basically using as an associative array (strings as keys and values). I want to use the array of keys as part of my application, but I'd like them to be in a specific order (not really an order that I can write an algorithm to sort them into). I could always store a separate array of the keys, but that seems kind of kludgey because I'd always have to update the keys of the dictionary as well as the values of the array, and make sure they always correspond. Currently I just use [myDictionary allKeys], but obviously this returns them in an arbitrary, non-guaranteed order. Is there a data structure in Objective-C that I'm missing? Does anyone have any suggestions on how to more elegantly do this?
9 Answers
The solution of having an associated NSMutableArray of keys isn't so bad. It avoids subclassing NSDictionary, and if you are careful with writing accessors, it shouldn't be too hard to keep synchronised.

- 146,289
- 39
- 203
- 257
-
2One pitfall is that NS(Mutable)Dictionary makes copies of keys, so the objects in the key array will be different. This can be problematic if a key is mutated. – Quinn Taylor Jun 20 '09 at 16:54
-
1That's a good point, but mitigated if the mutability is restricted to adding and removing object from the array rather than changing the items within them. – Abizern Jun 20 '09 at 18:54
-
1Not sure how you'd restrict someone modifying a key for which they provided a pointer in the first place. The array just stores a pointer to that key, and won't know if it changes or not. If the key is changed, you may not even be able to remove the added entry from the array at all, which can be a real synchronization problem if you array keeps keys that are no longer in the dictionary, or vice versa... :-) – Quinn Taylor Jun 20 '09 at 19:01
-
2BTW, my apologies if I sound overly critical. I've been dealing with this same problem myself, but since it's for a framework, I'm trying to design it to be robust and correct in every conceivable situation. You're correct that a separate array isn't *so* bad, but it's not as simple as a class that tracks it for you. Plus, there are numerous benefits if such a class extends NS(Mutable)Dictionary, since it could be used anywhere a Cocoa dictionary is required. – Quinn Taylor Jun 20 '09 at 19:15
-
1I don't mind the discussion. My suggestion was just a workaround. Writing a framework is a different proposition entirely and it is something that needs careful thought. Personally, I find mutability troublesome for this very reason, and I try to minimise the use of those classes in my own programs. – Abizern Jun 20 '09 at 20:35
-
@Quinn Taylor: Late to the party here, but couldn't you avoid this problem by having your mutable array for keys *also* copy the key object before inserting it, just as the dictionary does? – Ben Zotto Oct 17 '10 at 14:31
-
Not really, because then you'd have two different copies (different pointers) in the dictionary and array. What you want is to store the same pointer in both collections, so you can accurately find and/or remove objects which have been added, and which might have been mutated subsequently. Otherwise, the object might be removed from the dictionary but not the array, or vice versa – Quinn Taylor Oct 18 '10 at 18:53
-
1@Quinn Taylor: You can't mutate the key object in the dictionary-- that's why it copies the key to begin with; you no longer own it after setting it. The comparisons for existence in the dictionary are not based on a pointer compare. You should therefore be able to copy the key into your dictionary and build the correct semantics around it. – Ben Zotto Nov 02 '10 at 07:06
-
1"copy the key into your *array*..." – Ben Zotto Nov 02 '10 at 07:21
-
but why store the original key pointer in your array, why not obtain the copied key from the NSDictionary, and store (refcount) that in your array? – Motti Shneor Jun 30 '22 at 13:17
I'm late to the game with an actual answer, but you might be interested to investigate CHOrderedDictionary. It's a subclass of NSMutableDictionary which encapsulates another structure for maintaining key ordering. (It's part of CHDataStructures.framework.) I find it to be more convenient than managing a dictionary and array separately.
Disclosure: This is open-source code which I wrote. Just hoping it may be useful to others facing this problem.

- 2,078
- 1
- 16
- 25

- 44,553
- 16
- 113
- 131
-
1+1 - Haven't tried it yet but looked through the docs and it seems you've done some nice work here. I think it's a little embarrassing Apple is missing so many of these fundamentals. – whitneyland Oct 23 '11 at 20:18
-
1I don't think it's embarrassing, it's just a question of how they want their framework to develop. Specifically, new classes have to add a lot of value to be considered for inclusion in Foundation. It's not that complicated to pair a dictionary with a sorted array of keys, and Apple tries to contain the size (and maintainability) of the framework by not going overboard with stuff that some people might use. – Quinn Taylor Oct 25 '11 at 17:08
-
3It's not just that an ordered dictionary is missing, it's that so many useful CS101 collections are missing. I don't believe Objective-C would be a widely successful language without Apple, as opposed to C, C++, Java, C#, which have proved successful many times outside the purview of their creators. – whitneyland Oct 25 '11 at 17:47
-
1This. Is. Awesome. Shame I hadn't discovered this framework until now. This is gonna be a mainstay in most of the future projects. Thanks a LOT! – Dev Kanchen Feb 15 '12 at 12:26
-
1if the key is an NSString, would it be a problem to do the following ? create a dictionary as well as an array and have a common method to add and remove the data. Array contains list of NSString keys (in the desired order) Dictionary contains the NSString keys and the values – user1046037 May 23 '12 at 12:20
-
Thanks for updating the links in my answer, @Dolbz! Perfectly done. – Quinn Taylor Sep 24 '18 at 15:15
-
And thanks for the library @QuinnTaylor It makes what I was doing a lot cleaner – Dolbz Sep 26 '18 at 09:01
There is no such inbuilt method from which you can acquire this. But a simple logic work for you. You can simply add few numeric text in front of each key while you prepare the dictionary. Like
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
@"01.Created",@"cre",
@"02.Being Assigned",@"bea",
@"03.Rejected",@"rej",
@"04.Assigned",@"ass",
@"05.Scheduled",@"sch",
@"06.En Route",@"inr",
@"07.On Job Site",@"ojs",
@"08.In Progress",@"inp",
@"09.On Hold",@"onh",
@"10.Completed",@"com",
@"11.Closed",@"clo",
@"12.Cancelled", @"can",
nil];
Now if you can use sortingArrayUsingSelector while getting all keys in the same order as you place.
NSArray *arr = [[dict allKeys] sortedArrayUsingSelector:@selector(localizedStandardCompare:)];
At the place where you want to display keys in UIView, just chop off the front 3 character.

- 4,586
- 5
- 43
- 55
-
This shows how to remove the first three characters: http://stackoverflow.com/questions/1073872/how-to-remove-first-3-characters-from-nsstring – Leon Jun 05 '15 at 21:08
If you're going to subclass NSDictionary you need to implement these methods as a minimum:
- NSDictionary
-count
-objectForKey:
-keyEnumerator
- NSMutableDictionary
-removeObjectForKey:
-setObject:forKey:
- NSCopying/NSMutableCopying
-copyWithZone:
-mutableCopyWithZone:
- NSCoding
-encodeWithCoder:
-initWithCoder:
- NSFastEnumeration (for Leopard)
-countByEnumeratingWithState:objects:count:
The easiest way to do what you want is to make a subclass of NSMutableDictionary that contains its' own NSMutableDictionary that it manipulates and an NSMutableArray to store an ordered set of keys.
If you're never going to encode your objects you could conceivable skip implementing -encodeWithCoder:
and -initWithCoder:
All of your method implementations in the 10 methods above would then either go directly through your hosted dictionary or your ordered key array.

- 8,813
- 3
- 35
- 35
-
7There's one more that's non-obvious and tripped me up — if you implement NSCoding, also override -(Class)classForKeyedArchiver to return [self class]. Class clusters set this to always return the abstract parent class, so unless you change that, instances will always be decoded as an NS(Mutable)Dictionary. – Quinn Taylor Jun 20 '09 at 05:51
My little addition: sorting by numeric key (Using shorthand notations for smaller code)
// the resorted result array
NSMutableArray *result = [NSMutableArray new];
// the source dictionary - keys may be Ux timestamps (as integer, wrapped in NSNumber)
NSDictionary *dict =
@{
@0: @"a",
@3: @"d",
@1: @"b",
@2: @"c"
};
{// do the sorting to result
NSArray *arr = [[dict allKeys] sortedArrayUsingSelector:@selector(compare:)];
for (NSNumber *n in arr)
[result addObject:dict[n]];
}

- 3,221
- 35
- 38
Quick 'n dirty:
When you need to order your dictionary (herein called “myDict”), do this:
NSArray *ordering = [NSArray arrayWithObjects: @"Thing",@"OtherThing",@"Last Thing",nil];
Then, when you need to order your dictionary, create an index:
NSEnumerator *sectEnum = [ordering objectEnumerator];
NSMutableArray *index = [[NSMutableArray alloc] init];
id sKey;
while((sKey = [sectEnum nextObject])) {
if ([myDict objectForKey:sKey] != nil ) {
[index addObject:sKey];
}
}
Now, the *index object will contain the appropriate keys in the correct order. Note that this solution does not require that all the keys necessarily exist, which is the usual situation we're dealing with...

- 457
- 5
- 5
-
What about sortedArrayUsingSelector for the array order? https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/SortDescriptors/Articles/Creating.html – Alex Zavatone Mar 26 '14 at 15:39
Minimal implementation of an ordered subclass of NSDictionary (based on https://github.com/nicklockwood/OrderedDictionary). Feel free to extend for your needs:
Swift 3 and 4
class MutableOrderedDictionary: NSDictionary {
let _values: NSMutableArray = []
let _keys: NSMutableOrderedSet = []
override var count: Int {
return _keys.count
}
override func keyEnumerator() -> NSEnumerator {
return _keys.objectEnumerator()
}
override func object(forKey aKey: Any) -> Any? {
let index = _keys.index(of: aKey)
if index != NSNotFound {
return _values[index]
}
return nil
}
func setObject(_ anObject: Any, forKey aKey: String) {
let index = _keys.index(of: aKey)
if index != NSNotFound {
_values[index] = anObject
} else {
_keys.add(aKey)
_values.add(anObject)
}
}
}
usage
let normalDic = ["hello": "world", "foo": "bar"]
// initializing empty ordered dictionary
let orderedDic = MutableOrderedDictionary()
// copying normalDic in orderedDic after a sort
normalDic.sorted { $0.0.compare($1.0) == .orderedAscending }
.forEach { orderedDic.setObject($0.value, forKey: $0.key) }
// from now, looping on orderedDic will be done in the alphabetical order of the keys
orderedDic.forEach { print($0) }
Objective-C
@interface MutableOrderedDictionary<__covariant KeyType, __covariant ObjectType> : NSDictionary<KeyType, ObjectType>
@end
@implementation MutableOrderedDictionary
{
@protected
NSMutableArray *_values;
NSMutableOrderedSet *_keys;
}
- (instancetype)init
{
if ((self = [super init]))
{
_values = NSMutableArray.new;
_keys = NSMutableOrderedSet.new;
}
return self;
}
- (NSUInteger)count
{
return _keys.count;
}
- (NSEnumerator *)keyEnumerator
{
return _keys.objectEnumerator;
}
- (id)objectForKey:(id)key
{
NSUInteger index = [_keys indexOfObject:key];
if (index != NSNotFound)
{
return _values[index];
}
return nil;
}
- (void)setObject:(id)object forKey:(id)key
{
NSUInteger index = [_keys indexOfObject:key];
if (index != NSNotFound)
{
_values[index] = object;
}
else
{
[_keys addObject:key];
[_values addObject:object];
}
}
@end
usage
NSDictionary *normalDic = @{@"hello": @"world", @"foo": @"bar"};
// initializing empty ordered dictionary
MutableOrderedDictionary *orderedDic = MutableOrderedDictionary.new;
// copying normalDic in orderedDic after a sort
for (id key in [normalDic.allKeys sortedArrayUsingSelector:@selector(compare:)]) {
[orderedDic setObject:normalDic[key] forKey:key];
}
// from now, looping on orderedDic will be done in the alphabetical order of the keys
for (id key in orderedDic) {
NSLog(@"%@:%@", key, orderedDic[key]);
}

- 37,241
- 25
- 195
- 267
-
1Reading your Obj-C implementation, made me wonder - don't you lose the basic performance characteristics of an NSDictionary here? you search for items one-by-one, instead of using the hash? I think much better implementation is possible. – Motti Shneor Jun 30 '22 at 12:19
-
@MottiShneor The "search" isn't part of the implementation of `MutableOrderedDictionary`. It was only an example usage of it for alphabetical key sorting: feel free to use your ordered dictionary in any other way you need. – Cœur Jul 01 '22 at 05:02
-
But it is - you override NSDictionary's implementation of `objectForKey:` method - and your implementation (the basic way to obtain object for dictionary-key) is calling `indexForObject` which runs in O(N) (linear search in array) instead of the expected O(1) most hash-based collections provide. Why do that? – Motti Shneor Jul 28 '22 at 10:08
-
@MottiShneor `indexOfObject:` is done on an OrderedSet, not on an Array. Anyway, feel free to adapt to your needs and extend that minimal implementation by replacing the OrderedSet with a Dictionary if you need/prefer. Be sure to measure the actual performance gain in practice. – Cœur Jul 29 '22 at 18:31
For, Swift 3. Please try out the following approach
//Sample Dictionary
let dict: [String: String] = ["01.One": "One",
"02.Two": "Two",
"03.Three": "Three",
"04.Four": "Four",
"05.Five": "Five",
"06.Six": "Six",
"07.Seven": "Seven",
"08.Eight": "Eight",
"09.Nine": "Nine",
"10.Ten": "Ten"
]
//Print the all keys of dictionary
print(dict.keys)
//Sort the dictionary keys array in ascending order
let sortedKeys = dict.keys.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedAscending }
//Print the ordered dictionary keys
print(sortedKeys)
//Get the first ordered key
var firstSortedKeyOfDictionary = sortedKeys[0]
// Get range of all characters past the first 3.
let c = firstSortedKeyOfDictionary.characters
let range = c.index(c.startIndex, offsetBy: 3)..<c.endIndex
// Get the dictionary key by removing first 3 chars
let firstKey = firstSortedKeyOfDictionary[range]
//Print the first key
print(firstKey)

- 1,137
- 9
- 14
I don’t like C++ very much, but one solution that I see myself using more and more is to use Objective-C++ and std::map
from the Standard Template Library. It is a dictionary whose keys are automatically sorted on insertion. It works surprisingly well with either scalar types or Objective-C objects both as keys and as values.
If you need to include an array as a value, just use std::vector
instead of NSArray
.
One caveat is that you might want to provide your own insert_or_assign
function, unless you can use C++17 (see this answer). Also, you need to typedef
your types to prevent certain build errors. Once you figure out how to use std::map
, iterators etc., it is pretty straightforward and fast.

- 1,370
- 9
- 10