Iterator in Swift
Introduction to Iterators in Swift
An iterator in Swift is an object that allows traversing through a sequence of elements one at a time. Iterators are used to access collection elements without exposing their internal representation.
Swift provides built-in IteratorProtocol
, which enables custom iteration over collections like arrays, dictionaries, and custom data structures.
Key Features of Iterators in Swift:
- Sequential Access – Access elements one by one.
- Custom Iterators – Define custom iteration logic.
- Memory Efficiency – Process elements lazily.
- Supports Generators – Works with sequences and collections.
1. Built-in Iterators in Swift
Swift's collections (Array, Set, Dictionary) come with default iterators.
Example 1: Iterating Over an Array
let numbers = [10, 20, 30, 40]
var iterator = numbers.makeIterator()
while let number = iterator.next() {
print("Next number: \(number)")
}
Output
Next number: 20
Next number: 30
Next number: 40
.makeIterator()
creates an iterator.
.next()
fetches the next element.
Returns nil
when all elements are exhausted.
Example 2: Iterating Over a Dictionary
let cities = ["NY": "New York", "CA": "California"]
var cityIterator = cities.makeIterator()
while let city = cityIterator.next() {
print("Key: \(city.key), Value: \(city.value)")
}
Output
Key: CA, Value: California
Iterators work on key-value pairs.
2. Creating a Custom Iterator in Swift
To create a custom iterator, we implement IteratorProtocol
and define a next()
method.
Example 3: Creating a Custom Number Iterator
struct NumberIterator: IteratorProtocol {
var current = 1
mutating func next() -> Int? {
if current <= 5 {
let value = current
current += 1
return value
}
return nil
}
}
// Using the custom iterator
var numIterator = NumberIterator()
while let number = numIterator.next() {
print("Custom Iterator: \(number)")
}
Output
Custom Iterator: 2
Custom Iterator: 3
Custom Iterator: 4
Custom Iterator: 5
next()
returns one element at a time.
Stops when the limit is reached (nil
).
3. Creating a Custom Sequence with an Iterator
A sequence is a collection that provides an iterator.
Example 4: Implementing a Custom Sequence
struct CountSequence: Sequence {
var start: Int
var end: Int
func makeIterator() -> CountIterator {
return CountIterator(current: start, end: end)
}
}
// Custom Iterator
struct CountIterator: IteratorProtocol {
var current: Int
let end: Int
mutating func next() -> Int? {
guard current <= end else { return nil }
defer { current += 1 }
return current
}
}
// Using the custom sequence
let count = CountSequence(start: 1, end: 5)
for num in count {
print("Sequence: \(num)")
}
Output
Sequence: 2
Sequence: 3
Sequence: 4
Sequence: 5
makeIterator()
returns an iterator.
for-in
loop automatically calls .next()
.
4. Lazy Iterators for Performance Optimization
Lazy iterators process elements only when needed, improving efficiency.
Example 5: Using Lazy Iterators for Performance
let numbers = [1, 2, 3, 4, 5].lazy.map { $0 * 2 }
for num in numbers {
print("Lazy Value: \(num)")
}
Output
Lazy Value: 4
Lazy Value: 6
Lazy Value: 8
Lazy Value: 10
.lazy
processes only required elements.
5. Real-World Use Cases of Iterators
Use Case | Iterator Type |
---|---|
Traversing Arrays & Dictionaries | makeIterator() |
Building Custom Data Streams | Custom IteratorProtocol |
Efficient Processing of Large Data | Lazy Sequences |
Handling Infinite Data Streams | Infinite Iterators |
6. Infinite Iterators in Swift
An infinite iterator generates an endless sequence.
Example 6: Creating an Infinite Number Generator
struct InfiniteCounter: IteratorProtocol {
var current = 1
mutating func next() -> Int? {
defer { current += 1 }
return current
}
}
// Using Infinite Iterator
var counter = InfiniteCounter()
for _ in 1...5 {
print("Infinite Count: \(counter.next()!)")
}
Output
Infinite Count: 2
Infinite Count: 3
Infinite Count: 4
Infinite Count: 5
Never-ending iteration unless manually stopped.
7. Using Iterators in Functional Programming
Example 7: Filtering Elements with Iterators
let numbers = [1, 2, 3, 4, 5]
let filteredNumbers = numbers.lazy.filter { $0 % 2 == 0 }
for num in filteredNumbers {
print("Filtered Number: \(num)")
}
Output
Filtered Number: 4
lazy.filter {}
optimizes performance.
Conclusion
Iterators in Swift simplify sequential data access and enable custom traversal mechanisms. They improve efficiency, readability, and flexibility in handling collections and streams.