Bird
Raised Fist0
iOS Swiftmobile~20 mins

Async sequences in iOS Swift - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Async Numbers Stream
This screen shows numbers from 1 to 10 one by one with a 1-second delay using async sequences.
Target UI
-------------------------
| Async Numbers Stream  |
|-----------------------|
| Number:               |
|                       |
| [Start Stream]        |
-------------------------
Display a number starting from 1 to 10, updating every second.
Use Swift async sequences to generate the numbers asynchronously.
Show a button labeled 'Start Stream' that starts the async sequence when tapped.
Disable the button while the stream is running.
Update the displayed number on the screen as each number is received.
Starter Code
iOS Swift
import SwiftUI

struct AsyncNumbersStreamView: View {
    @State private var currentNumber: Int? = nil
    @State private var isStreaming = false

    var body: some View {
        VStack(spacing: 20) {
            Text("Number: \(currentNumber.map(String.init) ?? "")")
                .font(.largeTitle)
                .padding()

            Button("Start Stream") {
                // TODO: Start async sequence here
            }
            .disabled(isStreaming)
            .padding()
            .background(isStreaming ? Color.gray : Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
        }
        .padding()
    }
}

struct AsyncNumbersStreamView_Previews: PreviewProvider {
    static var previews: some View {
        AsyncNumbersStreamView()
    }
}
Task 1
Task 2
Task 3
Task 4
Solution
iOS Swift
import SwiftUI

struct AsyncNumbersStreamView: View {
    @State private var currentNumber: Int? = nil
    @State private var isStreaming = false

    var body: some View {
        VStack(spacing: 20) {
            Text("Number: \(currentNumber.map(String.init) ?? "")")
                .font(.largeTitle)
                .padding()

            Button("Start Stream") {
                Task {
                    await startNumberStream()
                }
            }
            .disabled(isStreaming)
            .padding()
            .background(isStreaming ? Color.gray : Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
        }
        .padding()
    }

    func numberAsyncSequence() -> AsyncStream<Int> {
        AsyncStream { continuation in
            Task {
                for number in 1...10 {
                    try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 second
                    continuation.yield(number)
                }
                continuation.finish()
            }
        }
    }

    func startNumberStream() async {
        isStreaming = true
        for await number in numberAsyncSequence() {
            currentNumber = number
        }
        isStreaming = false
    }
}

struct AsyncNumbersStreamView_Previews: PreviewProvider {
    static var previews: some View {
        AsyncNumbersStreamView()
    }
}

This solution uses AsyncStream to create an asynchronous sequence that yields numbers from 1 to 10 with a 1-second delay between each.

The startNumberStream() function runs asynchronously and updates the currentNumber state as each number is received, which updates the UI.

The button triggers this async function inside a Task to run asynchronously without blocking the UI.

The button is disabled while streaming to prevent multiple streams running at once.

Final Result
Completed Screen
-------------------------
| Async Numbers Stream  |
|-----------------------|
| Number: 1             |
|                       |
| [Start Stream]        |
-------------------------

(After 1 second)
-------------------------
| Async Numbers Stream  |
|-----------------------|
| Number: 2             |
|                       |
| [Start Stream]        |
-------------------------

... continues until Number: 10
User taps 'Start Stream' button.
Button disables to gray color.
Number updates every second from 1 to 10.
After 10, button re-enables for another run.
Stretch Goal
Add a 'Stop Stream' button that appears while streaming to cancel the number sequence early.
💡 Hint
Use a Task handle to cancel the running async task and reset states.

Practice

(1/5)
1. What is the main purpose of using async sequences in Swift?
easy
A. To perform synchronous loops faster
B. To create static arrays of data
C. To handle data that arrives over time asynchronously
D. To store data permanently on disk

Solution

  1. Step 1: Understand async sequences concept

    Async sequences allow handling data that comes in over time, not all at once.
  2. Step 2: Compare options with async sequence use

    Only To handle data that arrives over time asynchronously describes handling data arriving asynchronously, which matches async sequences.
  3. Final Answer:

    To handle data that arrives over time asynchronously -> Option C
  4. Quick Check:

    Async sequences = handle data over time [OK]
Hint: Async sequences handle data arriving over time [OK]
Common Mistakes:
  • Thinking async sequences create static data
  • Confusing async sequences with synchronous loops
  • Assuming async sequences store data permanently
2. Which of the following is the correct syntax to iterate over an async sequence named stream?
easy
A. for value in stream.await { print(value) }
B. for value in await stream { print(value) }
C. await for value in stream { print(value) }
D. for await value in stream { print(value) }

Solution

  1. Step 1: Recall async sequence iteration syntax

    Swift uses for await to loop over async sequences.
  2. Step 2: Match syntax with options

    Only for await value in stream { print(value) } uses for await value in stream, which is correct syntax.
  3. Final Answer:

    for await value in stream { print(value) } -> Option D
  4. Quick Check:

    Use 'for await' to loop async sequences [OK]
Hint: Use 'for await' before the loop variable [OK]
Common Mistakes:
  • Placing 'await' after 'for' incorrectly
  • Using 'await' inside the loop variable
  • Trying to access '.await' property on sequence
3. Given the async sequence numbers that yields 1, 2, 3, what will this code print?
for await num in numbers {
  print(num * 2)
}
medium
A. 2 4 6
B. 1 2 3
C. 0 2 4
D. Error: Cannot multiply async sequence

Solution

  1. Step 1: Understand the async sequence values

    The sequence yields 1, 2, and 3 asynchronously.
  2. Step 2: Calculate output inside loop

    Each number is multiplied by 2 and printed: 2, 4, 6.
  3. Final Answer:

    2 4 6 -> Option A
  4. Quick Check:

    Multiply each yielded value by 2 [OK]
Hint: Multiply each async value inside the loop [OK]
Common Mistakes:
  • Printing original values without multiplication
  • Expecting synchronous output order
  • Thinking async sequences cause errors here
4. What is wrong with this code snippet?
for num in numbers {
  print(num)
}

Assuming numbers is an async sequence.
medium
A. Should use 'while' loop instead of 'for'
B. Missing 'await' keyword before the loop variable
C. Async sequences cannot be iterated
D. Missing 'async' keyword in function declaration

Solution

  1. Step 1: Identify iteration syntax for async sequences

    Async sequences require 'for await' to iterate properly.
  2. Step 2: Check code snippet

    The code uses 'for num in numbers' without 'await', which is incorrect.
  3. Final Answer:

    Missing 'await' keyword before the loop variable -> Option B
  4. Quick Check:

    Async sequence loops need 'for await' [OK]
Hint: Always use 'for await' with async sequences [OK]
Common Mistakes:
  • Omitting 'await' in the loop
  • Thinking async sequences can't be iterated
  • Confusing async function declaration with loop syntax
5. You want to collect the first 3 values from an async sequence updates into an array. Which code correctly does this?
hard
A. var results = [] for await update in updates { results.append(update) if results.count == 3 { break } }
B. var results = [] for update in updates { results.append(update) if results.count == 3 { break } }
C. var results = [] while let update = await updates.next() { results.append(update) if results.count == 3 { break } }
D. var results = [] updates.forEach { update in results.append(update) if results.count == 3 { break } }

Solution

  1. Step 1: Understand async sequence iteration and breaking

    Use 'for await' to iterate async sequences and break when count reaches 3.
  2. Step 2: Evaluate each option

    var results = [] for await update in updates { results.append(update) if results.count == 3 { break } } uses 'for await' with break after 3 items, correct. var results = [] for update in updates { results.append(update) if results.count == 3 { break } } lacks 'await'. var results = [] while let update = await updates.next() { results.append(update) if results.count == 3 { break } } uses invalid syntax for async sequences. var results = [] updates.forEach { update in results.append(update) if results.count == 3 { break } } uses 'forEach' which doesn't support async iteration or breaking.
  3. Final Answer:

    var results = [] for await update in updates { results.append(update) if results.count == 3 { break } } -> Option A
  4. Quick Check:

    Use 'for await' and break after 3 items [OK]
Hint: Use 'for await' and break after collecting 3 items [OK]
Common Mistakes:
  • Omitting 'await' in the loop
  • Using synchronous loops on async sequences
  • Trying to use 'forEach' with async sequences
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