285

I am finding some difficulty in accessing mutable dictionary keys and values in Objective-C.

Suppose I have this:

NSMutableDictionary *xyz=[[NSMutableDictionary alloc] init]; 

I can set keys and values. Now, I just want to access each key and value, but I don't know the number of keys set.

In PHP it is very easy, something as follows:

foreach ($xyz as $key => $value) 

How is it possible in Objective-C?

7 Answers 7

689
for (NSString* key in xyz) { id value = xyz[key]; // do stuff } 

This works for every class that conforms to the NSFastEnumeration protocol (available on 10.5+ and iOS), though NSDictionary is one of the few collections which lets you enumerate keys instead of values. I suggest you read about fast enumeration in the Collections Programming Topic.

Oh, I should add however that you should NEVER modify a collection while enumerating through it.

Sign up to request clarification or add additional context in comments.

6 Comments

I was wondering, should'nt it have been: for (NSString* key in [xyz allKeys]) ?? Or does it not really matter.
@user76859403 Enumerating a dictionary, in fact, enumerates the keys. for (NSString* key in [xyz allKeys]) is conceptually the same thing.
Use [xyz allKeys] if you need to mutate the dictionary while enumerating the keys. See my answer below.
Is this loop return same order all the time? Or do we need another way to use it for TableView sections?
@ymutlu, Cocoa dictionaries are unordered. This means that the order in which they iterate may change whenever you modify them.
|
102

Just to not leave out the 10.6+ option for enumerating keys and values using blocks...

[dict enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) { NSLog(@"%@ = %@", key, object); }]; 

If you want the actions to happen concurrently:

[dict enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id key, id object, BOOL *stop) { NSLog(@"%@ = %@", key, object); }]; 

7 Comments

3 different ways to enumerate through a dictionary . . . heh, this reminds me of the "Strangest Language Feature" answer where VB has 7 different kinds of loops.
Well... objectEnumerator was added in 1994, the for(... in ...) in about 2006, and Blocks were added in 2009. The block form of enumeration is natural fallout.
This seems to be faster than the standard for...in construct: oneofthesedaysblog.com/block-vs-for-in-objective-c-enumeration
@lkraider, I commented on that post, which actually compares block-based enumeration with an old for loop, not the for...in construct.
What is the *stop for? How do you make use of it? Any reference?
|
16

If you need to mutate the dictionary while enumerating:

for (NSString* key in xyz.allKeys) { [xyz setValue:[NSNumber numberWithBool:YES] forKey:key]; } 

1 Comment

The reason is allKeys returns a copy of keys. So it's safe to mutate the dictionary.
5

The easiest way to enumerate a dictionary is

for (NSString *key in tDictionary.keyEnumerator) { //do something here; } 

where tDictionary is the NSDictionary or NSMutableDictionary you want to iterate.

Comments

5

I suggest you to read the Enumeration: Traversing a Collection’s Elements part of the Collections Programming Guide for Cocoa. There is a sample code for your need.

1 Comment

Those are good links, although the code @zneak posted is much simpler and faster, if you can build for 10.5+ or iPhone.
3

Fast enumeration was added in 10.5 and in the iPhone OS, and it's significantly faster, not just syntactic sugar. If you have to target the older runtime (i.e. 10.4 and backwards), you'll have to use the old method of enumerating:

NSDictionary *myDict = ... some keys and values ... NSEnumerator *keyEnum = [myDict keyEnumerator]; id key; while ((key = [keyEnum nextObject])) { id value = [myDict objectForKey:key]; ... do work with "value" ... } 

You don't release the enumerator object, and you can't reset it. If you want to start over, you have to ask for a new enumerator object from the dictionary.

Comments

2

You can use -[NSDictionary allKeys] to access all the keys and loop through it.

1 Comment

True, but this does create an extra autoreleased array, which can be quite wasteful, especially for dictionaries with lots of keys.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.