Bird
Raised Fist0
Swiftprogramming~30 mins

Sequence protocol for custom iteration in Swift - Mini Project: Build & Apply

Choose your learning style10 modes available
Sequence protocol for custom iteration
📖 Scenario: Imagine you have a collection of daily temperatures and you want to create a custom way to go through them one by one.
🎯 Goal: You will build a custom type that holds a list of temperatures and lets you iterate over them using Swift's Sequence protocol.
📋 What You'll Learn
Create a struct called TemperatureLog that stores an array of Int temperatures
Add a property called temperatures with the exact values [72, 75, 79, 80, 68]
Create a struct called TemperatureIterator that conforms to IteratorProtocol
Implement the next() method in TemperatureIterator to return the next temperature
Make TemperatureLog conform to Sequence by implementing the makeIterator() method
Print each temperature from TemperatureLog using a for loop
💡 Why This Matters
🌍 Real World
Custom sequences let you control how data is accessed step-by-step, useful for processing logs, sensor data, or any list where you want special rules for moving through items.
💼 Career
Understanding how to create custom sequences and iterators is important for Swift developers working on apps that handle streams of data, animations, or complex collections.
Progress0 / 4 steps
1
Create the TemperatureLog struct with temperatures
Create a struct called TemperatureLog with a property temperatures set to the array [72, 75, 79, 80, 68].
Swift
Hint

Use struct TemperatureLog { let temperatures = [72, 75, 79, 80, 68] } to create the data container.

2
Create TemperatureIterator struct conforming to IteratorProtocol
Create a struct called TemperatureIterator that conforms to IteratorProtocol. Add a property temperatures of type [Int] and an index property currentIndex initialized to 0.
Swift
Hint

Define struct TemperatureIterator: IteratorProtocol with the properties temperatures and currentIndex.

3
Implement next() method in TemperatureIterator
Inside TemperatureIterator, implement the next() method that returns the next temperature from temperatures or nil if at the end. Increase currentIndex after returning a value.
Swift
Hint

Use mutating func next() -> Int? and check if currentIndex is less than the array count to return the next temperature.

4
Make TemperatureLog conform to Sequence and print temperatures
Make TemperatureLog conform to Sequence by adding a makeIterator() method that returns a TemperatureIterator initialized with temperatures. Then, use a for loop to print each temperature from an instance of TemperatureLog.
Swift
Hint

Implement func makeIterator() -> TemperatureIterator returning TemperatureIterator(temperatures: temperatures). Then use for temp in log { print(temp) }.

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