The iterator pattern in design patterns is used in the Cocoa Touch framework

  • 2020-05-30 21:04:50
  • OfStack

A basic understanding
Iterator pattern (Iterrator) : provides a method to access elements in an aggregate object sequentially, without exposing the internal representation of that element.
You should consider using the iterator pattern when you access an aggregate object and need to traverse whatever the object is.
You need to traverse the aggregation in a variety of ways, so consider using the iterator pattern.
The iterator pattern separates the traversal behavior of the collection object and abstracts an iterator class to take care of it. In this way, the internal structure of the collection can not be exposed, and the data inside the collection can be transparently accessed by external code.
An iterator defines an interface to access a collection element and record the current element.
Different iterators can execute different iteration strategies.
External and internal iterators:

External iterator

The external iterator lets the client manipulate the iteration process directly, so the client needs to know about the external iterator in order to use it. But it gives the client more control The client creates and maintains external iterators Clients can implement multiple types of traversal using different external iterators

Internal iterator

The client does not need to know about any external iterators, but can either access one element at a time through the special interface of the collection object, or send a message to each element in the collection. The collection object itself creates and maintains its external iterators A collection object can select a different external iterator without modifying the client code

Using the iterator pattern in the Cocoa Touch framework?

The NSEnumerator class in the foundation framework implements the iterator pattern. The private concrete subclass of the abstract NSEnumerator class returns the enumerator object, which can traverse the various collections -- arrays, collections, dictionaries -- in sequence, returning the objects in the collection to the client.

NSDirectoryEnumerator, an instance of this class recursively enumerates the contents of a directory in the file system. Collection classes such as NSArray, NSSet, and NSDictionary define methods that return instances of the NSEnumerator subclass corresponding to the collection type. All enumerators work in the same way, sending an nextObject message to the enumerator in a loop, fetching the object from the enumerator until it returns nil to indicate the end of the traversal.
1.NSEnumerator

We can use NSEnumerator to enumerate elements in NSArray, NSDictionary, and NSSet objects. NSEnumerator itself is an abstract class that relies on several factory methods, such as objectEnumrator or keyEnumerator, to create and return the corresponding concrete enumerator object. The code is as follows:


 NSArray *array = @[@" zhang 3", @" li 4", @" The king 5"];
    NSEnumerator *itemEnumerator = [array objectEnumerator];
    
    NSString *item;
    while (item = [itemEnumerator nextObject]) {
        NSLog(@"item is :%@", item);
    }


2015-08-28 16:48:05.463 NSEnumatroDemo[55301:3712762] item is : zhang 3
2015-08-28 16:48:05.463 NSEnumatroDemo[55301:3712762] item is : li 4
2015-08-28 16:48:05.464 NSEnumatroDemo[55301:3712762] item is : The king 5

The array is traversed using NSEnumerator, and when the message is called [itemEnumerator nextObject], nil is returned, and the enumeration process ends.

2. Block-based enumeration

Since iOS4.0, new methods have been introduced in NSArray, NSDictionary, and NSSet objects for block-based enumeration. One method is called enumerateObjectsUsingBlock:(void(^)(id obj, NSUInteger idx, BOOL *stop))block. We can embed our algorithm definition in a block within the message call, or we can predefine a block somewhere else and pass it as a parameter to the message call. The following code:


NSArray *array = @[@" zhang 3", @" li 4", @" The king 5"];
NSString *str = @" li 4";
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
     NSLog(@"item is :%@", obj);
        
     if ([obj localizedStandardCompare:str] == NSOrderedSame) {
         *stop = YES;
         NSLog(@" Stop traversal ");
     }
}];


2015-08-28 17:10:03.556 NSEnumatroDemo[55478:3723216] item is : zhang 3
2015-08-28 17:10:03.557 NSEnumatroDemo[55478:3723216] item is : li 4
2015-08-28 17:10:03.557 NSEnumatroDemo[55478:3723216]  Stop traversal 

If there is a string "lee 4" in the array array, set the pointer *stop to YES to notify the array object to stop traversing earlier.

The block-based enumeration in NSSet objects is very similar to that in NSArray, except that there are no idx parameters in the parameters of the block. Because the elements in the set are unordered.

One important benefit of using the internal iterators of NSArray, NSDictionary, and NSSet is that the algorithms that process their content can be defined elsewhere by other developers. Unlike the traditional algorithm defined in the for loop, well-defined blocks can be reused. As the blocks get larger, you can put them in separate implementation files, instead of squeezing them into 1 with the rest of the code.

3. Quick enumeration

An enumeration is provided after iOS 2.0. Quick enumeration is also recommended by apple. It allows the enumeration of collection objects to be used directly as part 1 of the for loop, without the need for other enumeration objects, and is more efficient than the for loop of the traditional opportunity index. The enumeration loop now USES pointer arithmetic to make it more efficient than the standard NSEnumerator method.

To use a quick enumeration, the collection class needs to implement the NSFastEnumeration protocol to provide the runtime with the necessary information about the collection. All collection classes and NSEnumerator classes in the base framework support fast enumeration. So you don't have to use the while loop to enumerate each element from NSEnumerator until nextObject returns nil. The code is as follows:


NSArray *array = @[@" zhang 3", @" li 4", @" The king 5"];
    for (id item in array) {
        NSLog(@"item is :%@", item);
    }


2015-08-28 17:28:18.619 NSEnumatroDemo[55596:3730966] item is : zhang 3
2015-08-28 17:28:18.620 NSEnumatroDemo[55596:3730966] item is : li 4
2015-08-28 17:28:18.620 NSEnumatroDemo[55596:3730966] item is : The king 5

4. Internal enumeration

NSArray has an instance method called (void)makeObjectsPerformSelector (SEL)aSelector, which allows the client to send one message to each element in the array and have each element execute the specified aSelector. You can use any of the previous enumeration methods to get each element to perform the same selector for the same purpose. This method internally enumerates the collection and sends an performSelector: message to each element. The disadvantage of this approach is that if any element in the collection does not respond to the selector, an exception is thrown. It is therefore primarily used for simple operations that do not require much runtime checking.


Related articles: