Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Fast Enumeration (looping) work in Objective-C? (ie: for (NSString *aString in aDictionary)...)

I'm working on implementing a customized searchBar for a fairly complex table and have come across this code pattern AGAIN. This is a sample from the Beginning iPhone Development book:

- (void)handleSearchForTerm:(NSString *)searchTerm
 {
NSMutableArray *sectionsToRemove = [[NSMutableArray alloc] init];
[self resetSearch];

for (NSString *key in self.keys)
  {
    NSMutableArray *array = [self.names valueForKey:key];
    NSMutableArray *toRemove = [[NSMutableArray alloc] init];
    for (NSString *name in array)
    {
        if ([name rangeOfString:searchTerm
                      options:NSCaseInsensitiveSearch].location == NSNotFound)
            [toRemove addObject:name];
    }

    if ([array count] == [toRemove count])
        [sectionsToRemove addObject:key];
    [array removeObjectsInArray:toRemove];
    [toRemove release];
  }
[self.keys removeObjectsInArray:sectionsToRemove];
[sectionsToRemove release];
[table reloadData];
}

The part I'm curious about is the "for (NSString *name in array)" section. What is this doing exactly? It seems to create a string for every item in the array. Also, how does this work with dictionaries?

Thanks!

like image 786
Jonah Avatar asked Aug 21 '09 20:08

Jonah


2 Answers

This construct is a different kind of for loop that runs over items in an Objective-C collection, rather than a C array. The first part defines an object that is being set to one element in the collection each run of the loop, while the second part is the collection to enumerate. For example, the code:

NSArray *array = [NSArray arrayWithObjects:@"foo", @"bar", nil];
for(NSString *string in array) {
    NSLog(string);
}

would print:

foo
bar

It's defining an NSString *string that, each run of the loop, gets set to the next object in the NSArray *array.

Similarly, you can use enumeration with instances of NSSet (where the order of objects aren't defined) and NSDictionary (where it will enumerate over keys stored in the dictionary - you can enumerate over the values by enumerating over keys, then calling valueForKey: on the dictionary using that key).

It's extremely similar to the construct in C:

int array[2] = { 0, 1 };
for(int i = 0; i < 2; i++) {
    printf("%d\n", array[i]);
}

which prints:

0
1

It's just a syntactical way of making the code more readable and hiding some of the fancy enumeration that goes into listing objects in an NSArray, NSSet, or NSDictionary. More detail is given in the Fast Enumeration section of The Objective-C 2.0 Programming Language document.

like image 200
Tim Avatar answered Oct 20 '22 00:10

Tim


This is called fast enumeration. It loops through the array, setting key to each item. It's the same, functionally, as doing this:

NSString *key;
for ( NSInteger i = 0; i < [[ self keys ] count ]; i++ ) {
    key = [[ self keys ] objectAtIndex:i ];

    NSMutableArray *array = [self.names valueForKey:key];
    NSMutableArray *toRemove = [[NSMutableArray alloc] init];
    for (NSString *name in array)
    {
            if ([name rangeOfString:searchTerm
                  options:NSCaseInsensitiveSearch].location == NSNotFound)
                    [toRemove addObject:name];
    }

    if ([array count] == [toRemove count])
            [sectionsToRemove addObject:key];
    [array removeObjectsInArray:toRemove];
    [toRemove release];
}
like image 33
Jeff Kelley Avatar answered Oct 20 '22 01:10

Jeff Kelley