Apple's documentation for enumeration begins with the familiar for in statement before moving swiftly to the more complex block-based enumeration. This is a leap in complexity and most people are probably mentally exhausted before reaching the final item on the page - 'Using an Enumerator' - which is based around a simple and useful class with only two methods.
This is a great shame because the class, NSEnumerator, is so simple that it can be entirely covered in a brief piece of example code:
And I'm sure it would be useful to many currently using for in statements. Not only this, but it will help to make block-based enumeration clearer as well.
The only warning to heed is Apple's statement that:
"It is not safe to modify a mutable collection while enumerating through it. Some enumerators may currently allow enumeration of a collection that is modified, but this behavior is not guaranteed to be supported in the future."
This is a great shame because the class, NSEnumerator, is so simple that it can be entirely covered in a brief piece of example code:
NSArray *anArray = @[@"hello",@"world"];
NSEnumerator *enumerator = [anArray objectEnumerator];
id object;
while ((object = [enumerator nextObject])) {
NSLog(@"Array item: %@",object);
}
NSDictionary *aDictionary = @{@"hello":@"Weird",@"world":@"Home"};
NSEnumerator *enumeratorDictionary = [aDictionary keyEnumerator];
id objectKey;
while ((objectKey = [enumeratorDictionary nextObject])) {
NSLog(@"Key: %@",objectKey);
}
NSArray *allObjects = [enumeratorDictionary allObjects]; //
NSLog(@"All objects after enumerator %@", allObjects); // Empty - because the enumator releases each object every time it has been called by nextObject
NSEnumerator *enumeratorDictionaryValues = [aDictionary objectEnumerator];
id objectValue;
NSArray *allValues = [enumeratorDictionaryValues allObjects];
NSLog(@"All values before enumerator %@", allValues); // Full - because the enumator hasn't called nextObject yet
while ((objectValue = [enumeratorDictionaryValues nextObject])) {
// Empty because allObjects have been retrieved
NSLog(@"Value: %@",allValues);
}
NSEnumerator *enumerator = [anArray objectEnumerator];
id object;
while ((object = [enumerator nextObject])) {
NSLog(@"Array item: %@",object);
}
NSDictionary *aDictionary = @{@"hello":@"Weird",@"world":@"Home"};
NSEnumerator *enumeratorDictionary = [aDictionary keyEnumerator];
id objectKey;
while ((objectKey = [enumeratorDictionary nextObject])) {
NSLog(@"Key: %@",objectKey);
}
NSArray *allObjects = [enumeratorDictionary allObjects]; //
NSLog(@"All objects after enumerator %@", allObjects); // Empty - because the enumator releases each object every time it has been called by nextObject
NSEnumerator *enumeratorDictionaryValues = [aDictionary objectEnumerator];
id objectValue;
NSArray *allValues = [enumeratorDictionaryValues allObjects];
NSLog(@"All values before enumerator %@", allValues); // Full - because the enumator hasn't called nextObject yet
while ((objectValue = [enumeratorDictionaryValues nextObject])) {
// Empty because allObjects have been retrieved
NSLog(@"Value: %@",allValues);
}
And I'm sure it would be useful to many currently using for in statements. Not only this, but it will help to make block-based enumeration clearer as well.
The only warning to heed is Apple's statement that:
"It is not safe to modify a mutable collection while enumerating through it. Some enumerators may currently allow enumeration of a collection that is modified, but this behavior is not guaranteed to be supported in the future."
Comments
Post a Comment