What if you could make your own collections that just work with Swift's loops, no extra hassle?
Why Sequence protocol for custom iteration in Swift? - Purpose & Use Cases
Imagine you have a list of items and you want to go through each one, but the way you want to go through them is special -- maybe skipping some, or combining steps. Doing this by hand means writing lots of loops and checks everywhere.
Manually writing loops for every special way to go through items is slow and tiring. It's easy to make mistakes, forget to update all loops if the rules change, and your code becomes messy and hard to read.
The Sequence protocol lets you define exactly how to go through your items once, in one place. Then you can use simple loops everywhere else, and your special rules happen automatically and cleanly.
var i = 0 while i < items.count { if shouldInclude(items[i]) { print(items[i]) } i += 1 }
struct CustomSequence: Sequence {
func makeIterator() -> some IteratorProtocol {
// custom iterator logic here
return CustomIterator()
}
}
struct CustomIterator: IteratorProtocol {
mutating func next() -> ItemType? {
// custom iteration logic here
}
}
for item in CustomSequence() {
print(item)
}You can create your own easy-to-use collections that work naturally with Swift's powerful loops and functions.
Think of a music playlist app that skips songs you dislike automatically when you play through the list. Using Sequence, the app can handle this skipping inside the playlist itself, so the player just plays songs one by one without extra checks.
Manual loops for custom steps are slow and error-prone.
Sequence protocol lets you define iteration once, cleanly.
Use simple loops everywhere else with your custom rules built-in.
Practice
Sequence protocol in Swift require you to provide for custom iteration?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 anext()method that returns the next element ornilwhen done.Final Answer:
An iterator with anext()method that returns elements ornil-> Option DQuick Check:
Sequence needsnext()iterator method = C [OK]
- Thinking Sequence requires a start() method
- Assuming all elements must be stored in an array
- Confusing count with iteration method
IteratorProtocol in Swift?Solution
Step 1: Check protocol conformance and method signature
IteratorProtocol requires anext()method returning an optional element type, hereInt?.Step 2: Validate each option
struct MyIterator: IteratorProtocol { func next() -> Int? { return nil } } correctly declares a struct conforming to IteratorProtocol withnext() -> Int?. class MyIterator { func next() -> Int { return 0 } } lacks conformance and returns non-optional. struct MyIterator: Sequence { func next() -> Int? { return nil } } wrongly conforms to Sequence, not IteratorProtocol. struct MyIterator: IteratorProtocol { func next() -> Int { return 0 } } returns non-optionalInt, which is incorrect.Final Answer:
struct MyIterator: IteratorProtocol { func next() -> Int? { return nil } } -> Option AQuick Check:
IteratorProtocol requires next() returning optional = D [OK]
- Returning non-optional from next()
- Confusing Sequence with IteratorProtocol
- Missing protocol conformance declaration
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?Solution
Step 1: Understand the iterator logic
The iterator starts atstart(3). It returnscurrentif > 0, then decreasescurrentby 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 BQuick Check:
CountDown from 3 to 1 = 3 2 1 [OK]
- Including 0 in output though iteration stops before
- Assuming count goes up instead of down
- Misreading defer behavior
struct MySequence: Sequence {
func makeIterator() -> MyIterator {
return MyIterator()
}
}
struct MyIterator: IteratorProtocol {
var count = 3
func next() -> Int? {
if count == 0 { return nil }
count -= 1
return count
}
}
What is the main problem here?Solution
Step 1: Identify mutability issue in next()
Thenext()method tries to changecount, but it is declared in a struct andnext()is not markedmutating.Step 2: Understand Swift struct rules
In structs, methods that modify properties must be markedmutating. Without it, the compiler will error.Final Answer:
next()is afuncbut modifiescount, which is a struct property -> Option AQuick Check:
Mutating methods must be marked mutating = A [OK]
- Forgetting mutating keyword on next()
- Thinking return type must be non-optional
- Confusing return type with protocol requirement
Sequence protocol for this?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 CQuick Check:
Use if check and increment after return for correct iteration = B [OK]
- Using while loop inside iterator closure causing single return
- Incrementing before returning causing off-by-one errors
- Incorrect start value causing wrong first element
Ready to prove it?
Pass the test and this pattern moves unknown
