Bird
Raised Fist0
Swiftprogramming~10 mins

Sequence protocol for custom iteration in Swift - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Sequence protocol for custom iteration
Define Sequence struct/class
↓
Implement makeIterator() method
↓
Create Iterator struct/class
↓
Implement next() method
↓
Use for-in loop to iterate
↓
next() returns next element or nil
↓
Iteration ends when next() returns nil
This flow shows how to create a custom sequence by defining a type that returns an iterator, which produces elements one by one until none are left.
Execution Sample
Swift
struct Countdown: Sequence {
  let start: Int
  func makeIterator() -> Iterator {
    Iterator(current: start)
  }
  struct Iterator: IteratorProtocol {
    var current: Int
    mutating func next() -> Int? {
      if current <= 0 { return nil }
      defer { current -= 1 }
      return current
    }
  }
}

for number in Countdown(start: 3) {
  print(number)
}
This code defines a Countdown sequence that counts down from a start number to 1, printing each number.
Execution Table
Stepcurrent (Iterator)Condition (current <= 0)ActionOutput
13falsereturn 3, current becomes 23
22falsereturn 2, current becomes 12
31falsereturn 1, current becomes 01
40truereturn nil (end iteration)nil
💡 Iteration stops when next() returns nil because current is 0
Variable Tracker
VariableStartAfter 1After 2After 3Final
current32100
Key Moments - 2 Insights
Why does the iteration stop when current reaches 0?
Because in the next() method, when current <= 0, it returns nil, signaling the end of iteration as shown in execution_table step 4.
Why do we use 'defer { current -= 1 }' instead of subtracting before returning?
Using defer ensures the current value is returned first, then decreased. This matches the output sequence seen in execution_table steps 1-3.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the value of 'current' after step 2?
A2
B0
C1
D3
💡 Hint
Check the 'current' column in execution_table row for step 2 and after 2.
At which step does the next() method return nil, ending the iteration?
AStep 1
BStep 4
CStep 3
DStep 2
💡 Hint
Look at the 'Output' column in execution_table where output is nil.
If we change 'start' to 5, how many times will next() return a number before nil?
A5 times
B3 times
C4 times
D6 times
💡 Hint
Refer to variable_tracker and execution_table pattern for how many numbers are returned from start down to 1.
Concept Snapshot
Sequence protocol requires a makeIterator() method.
IteratorProtocol requires a next() method returning next element or nil.
Use for-in loops to iterate custom sequences.
next() returning nil ends iteration.
Use defer to update state after returning current value.
Full Transcript
This example shows how to create a custom sequence in Swift by defining a struct that conforms to Sequence. The struct provides a makeIterator() method that returns an iterator. The iterator conforms to IteratorProtocol and implements next(), which returns the next element or nil when done. The countdown example starts from a number and counts down to 1. Each call to next() returns the current number and then decreases it. When current reaches zero, next() returns nil, ending the iteration. The for-in loop uses this to print each number. The execution table traces each call to next(), showing current value, condition check, action, and output. The variable tracker shows how current changes after each step. Key moments clarify why iteration stops and why defer is used. The quiz tests understanding of variable changes and iteration end. This teaches how to build and use custom sequences in Swift simply and clearly.

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

  1. Step 1: Understand the Sequence protocol requirement

    The Sequence protocol requires an iterator that can provide elements one by one.
  2. Step 2: Identify the iterator method

    This iterator must have a next() method that returns the next element or nil when done.
  3. Final Answer:

    An iterator with a next() method that returns elements or nil -> Option D
  4. 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 } }
C. struct MyIterator: Sequence { func next() -> Int? { return nil } }
D. struct MyIterator: IteratorProtocol { func next() -> Int? { return nil } }

Solution

  1. Step 1: Check protocol conformance and method signature

    IteratorProtocol requires a next() method returning an optional element type, here Int?.
  2. Step 2: Validate each option

    struct MyIterator: IteratorProtocol { func next() -> Int? { return nil } } correctly declares a struct conforming to IteratorProtocol with next() -> 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-optional Int, which is incorrect.
  3. Final Answer:

    struct MyIterator: IteratorProtocol { func next() -> Int? { return nil } } -> Option A
  4. Quick Check:

    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

  1. Step 1: Understand the iterator logic

    The iterator starts at start (3). It returns current if > 0, then decreases current by 1 after returning.
  2. 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.
  3. Final Answer:

    3 2 1 -> Option B
  4. 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:
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?
medium
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

  1. 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.
  2. Step 2: Understand Swift struct rules

    In structs, methods that modify properties must be marked mutating. Without it, the compiler will error.
  3. Final Answer:

    next() is a func but modifies count, which is a struct property -> Option A
  4. 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

  1. 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.
  2. 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.
  3. 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
  4. 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 unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard