The Sequence protocol lets you create your own collections that can be looped over with a for-in loop. It helps you make custom lists that work like arrays.
When you want to make a custom list of items that can be looped through easily.
When you have a special data structure and want to use <code>for-in</code> loops on it.
When you want to control how items are given one by one from your collection.
When you want to create a sequence that generates values on the fly, like numbers or dates.
Syntax
Swift
struct MySequence: Sequence {
func makeIterator() -> some IteratorProtocol {
// return an iterator here
}
}
struct MyIterator: IteratorProtocol {
mutatingfunc next() -> Element? {
// return next element or nil
}
}
You must provide a makeIterator() method that returns an iterator.
The iterator must have a next() method that returns the next item or nil when done.
Examples
This example creates a countdown sequence from a start number down to zero.
Swift
struct CountDown: Sequence {
let start: Intfunc makeIterator() -> CountDownIterator {
CountDownIterator(current: start)
}
}
struct CountDownIterator: IteratorProtocol {
var current: Intmutatingfunc next() -> Int? {
if current < 0 { returnnil }
defer { current -= 1 }
return current
}
}
This example creates a sequence of even numbers up to a max value using a closure-based iterator.
Swift
struct EvenNumbers: Sequence {
let max: Intfunc makeIterator() -> AnyIterator<Int> {
var current = 0return AnyIterator {
guard current <= max else { returnnil }
let result = current
current += 2return result
}
}
}
Sample Program
This program counts down from 3 to 0 by looping over a custom sequence.
Swift
struct CountDown: Sequence {
let start: Intfunc makeIterator() -> CountDownIterator {
CountDownIterator(current: start)
}
}
struct CountDownIterator: IteratorProtocol {
var current: Intmutatingfunc next() -> Int? {
if current < 0 { returnnil }
defer { current -= 1 }
return current
}
}
let countdown = CountDown(start: 3)
for number in countdown {
print(number)
}
OutputSuccess
Important Notes
Use mutating on next() because it changes the iterator's state.
Returning nil from next() means the sequence ended.
You can use AnyIterator to simplify iterator creation with closures.
Summary
The Sequence protocol lets you make custom collections that work with for-in loops.
You must provide an iterator with a next() method that returns items or nil.
This helps you create flexible and reusable ways to loop over your own data.
Practice
(1/5)
1. What does the Sequence protocol in Swift require you to provide for custom iteration?
easy
A. A property that stores all elements in an array
B. A method named start() that begins the iteration
C. A function that returns the count of elements
D. An iterator with a next() method that returns elements or nil
Solution
Step 1: Understand the Sequence protocol requirement
The Sequence protocol requires an iterator that can provide elements one by one.
Step 2: Identify the iterator method
This iterator must have a next() method that returns the next element or nil when done.
Final Answer:
An iterator with a next() method that returns elements or nil -> Option D
Quick Check:
Sequence needs next() iterator method = C [OK]
Hint: Sequence needs an iterator with next() returning nil at end [OK]
Common Mistakes:
Thinking Sequence requires a start() method
Assuming all elements must be stored in an array
Confusing count with iteration method
2. Which of the following is the correct way to declare a custom iterator type conforming to IteratorProtocol in Swift?
easy
A. struct MyIterator: IteratorProtocol { func next() -> Int { return 0 } }
B. class MyIterator { func next() -> Int { return 0 } }
IteratorProtocol requires next() returning optional = D [OK]
Hint: IteratorProtocol's next() must return optional element type [OK]
Common Mistakes:
Returning non-optional from next()
Confusing Sequence with IteratorProtocol
Missing protocol conformance declaration
3. Consider this Swift code implementing a custom sequence:
struct CountDown: Sequence {
let start: Int
func makeIterator() -> some IteratorProtocol {
var current = start
return AnyIterator {
if current <= 0 { return nil }
defer { current -= 1 }
return current
}
}
}
for number in CountDown(start: 3) {
print(number)
}
What is the output?
medium
A. 3 2 1 0
B. 3 2 1
C. 4 3 2 1
D. 1 2 3
Solution
Step 1: Understand the iterator logic
The iterator starts at start (3). It returns current if > 0, then decreases current by 1 after returning.
Step 2: Trace the iteration values
First call returns 3, then current becomes 2. Next returns 2, current becomes 1. Next returns 1, current becomes 0. Next call returns nil because current is 0, ending iteration.
Final Answer:
3 2 1 -> Option B
Quick Check:
CountDown from 3 to 1 = 3 2 1 [OK]
Hint: Check when next() returns nil to find iteration end [OK]
Common Mistakes:
Including 0 in output though iteration stops before
Assuming count goes up instead of down
Misreading defer behavior
4. This code attempts to create a custom sequence but has an error:
A. next() is a func but modifies count, which is a struct property
B. makeIterator() should return IteratorProtocol instead of MyIterator
C. count should start at 0, not 3
D. next() must return non-optional Int
Solution
Step 1: Identify mutability issue in next()
The next() method tries to change count, but it is declared in a struct and next() is not marked mutating.
Step 2: Understand Swift struct rules
In structs, methods that modify properties must be marked mutating. Without it, the compiler will error.
Final Answer:
next() is a func but modifies count, which is a struct property -> Option A
Quick Check:
Mutating methods must be marked mutating = A [OK]
Hint: Mark methods mutating if they change struct properties [OK]
Common Mistakes:
Forgetting mutating keyword on next()
Thinking return type must be non-optional
Confusing return type with protocol requirement
5. You want to create a custom sequence that iterates over only even numbers from 2 up to a given limit. Which implementation correctly uses the Sequence protocol for this?
hard
A. struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 2
return AnyIterator {
while current <= limit {
let result = current
current += 2
return result
}
return nil
}
}
}
B. struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 0
return AnyIterator {
current += 2
if current < limit {
return current
}
return nil
}
}
}
C. struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 2
return AnyIterator {
if current <= limit {
let result = current
current += 2
return result
}
return nil
}
}
}
D. struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 0
return AnyIterator {
if current < limit {
current += 2
return current
}
return nil
}
}
}
Solution
Step 1: Check iterator logic for even numbers
The iterator should start at 2 and return current if <= limit, then add 2 for next call.
Step 2: Analyze each option's iteration behavior
struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 2
return AnyIterator {
while current <= limit {
let result = current
current += 2
return result
}
return nil
}
}
} uses a while loop inside the closure, which causes it to return only once and then exit, so it won't iterate properly. struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 2
return AnyIterator {
if current <= limit {
let result = current
current += 2
return result
}
return nil
}
}
} uses an if check and returns current then increments, correctly producing even numbers up to limit. struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 0
return AnyIterator {
current += 2
if current < limit {
return current
}
return nil
}
}
} increments before checking, so first returned number is 2, which is correct, but starts at 0 which is okay. struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 0
return AnyIterator {
if current < limit {
current += 2
return current
}
return nil
}
}
} increments after checking current < limit, so it may skip the limit if limit is even. struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 2
return AnyIterator {
if current <= limit {
let result = current
current += 2
return result
}
return nil
}
}
} is the clearest and correct implementation.
Final Answer:
struct EvenNumbers: Sequence {
let limit: Int
func makeIterator() -> AnyIterator<Int> {
var current = 2
return AnyIterator {
if current <= limit {
let result = current
current += 2
return result
}
return nil
}
}
} -> Option C
Quick Check:
Use if check and increment after return for correct iteration = B [OK]
Hint: Use if condition inside iterator closure, not while loop [OK]
Common Mistakes:
Using while loop inside iterator closure causing single return
Incrementing before returning causing off-by-one errors
Incorrect start value causing wrong first element
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.