views:

925

answers:

3

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!

+8  A: 

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.

Tim
+1  A: 

It's a for loop with one iteration for each key in the dictionary.

The for..in construct is called Fast enumeration. You can read more about it in Objective-C 2.0 Programming Guide.

How it works with an object depends on it's implementation of the NSFastEnumeration protocol. The NSDictionary class reference describes how it works with dictionaries:

On Mac OS X v10.5 and later, NSDictionary supports the NSFastEnumeration protocol. You can use the for…in construct to enumerate the keys of a dictionary, as illustrated in the following example.

Jaka Jančar
+3  A: 

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];
}
Jeff Kelley