Iterator Design Pattern in Swift

1. Definition

The Iterator pattern provides a way to access the elements of an aggregate object (like a collection) sequentially without exposing its underlying representation. It abstracts the traversal of different data structures, allowing new types of collections to be processed using the same iteration code.

2. Problem Statement

Imagine you have different collection types (arrays, dictionaries, trees) and you want to traverse through their items without having to know the details of their internal structures.

3. Solution

Implement an iterator that encapsulates the details of accessing and traversing the items in the collection.

4. Real-World Use Cases

1. Traversing diverse collection types without direct access to their underlying representations.

2. Pagination in databases.

3. Navigating items in a custom UI list component.

5. Implementation Steps

1. Define an Iterator protocol that declares methods for traversal.

2. Implement concrete Iterators for different collection types.

3. Provide a unified way to access different collections through these Iterators.

6. Implementation in Swift Programming

// 1. Iterator Protocol
protocol Iterator {
    associatedtype Element
    func hasNext() -> Bool
    mutating func next() -> Element?
}
// 2. Concrete Iterator for an Array
struct ArrayIterator<Element>: Iterator {
    private let array: [Element]
    private var index = 0
    init(array: [Element]) {
        self.array = array
    }
    func hasNext() -> Bool {
        return index < array.count
    }
    mutating func next() -> Element? {
        if hasNext() {
            let element = array[index]
            index += 1
            return element
        }
        return nil
    }
}
// 3. Using the Iterator
var numbers = [1, 2, 3, 4, 5]
var iterator = ArrayIterator(array: numbers)
while iterator.hasNext() {
    print(iterator.next()!)
}

Output:

1
2
3
4
5

Explanation:

1. The Iterator protocol defines methods to traverse a collection.

2. ArrayIterator is a concrete implementation of the Iterator for arrays.

3. In the client code, we created an iterator for an array of numbers and printed each number.

7. When to use?

Use the Iterator pattern when:

1. You need a standardized way to traverse different collections.

2. You want to provide a clean API for iteration without exposing the internal representation.

3. You have complex data structures, like trees or graphs, and you want to hide the complexity of traversal from the client.


Comments