Range Over Channels in Swift

Our example demonstrates how to iterate over values received from a channel using a for-in loop in Swift.

import Foundation

func main() {
    // We'll iterate over 2 values in the `queue` channel.
    let queue = DispatchQueue(label: "com.example.queue")
    let semaphore = DispatchSemaphore(value: 0)
    var values = ["one", "two"]
    
    // This closure simulates sending values to the channel
    queue.async {
        for value in values {
            print(value)
            semaphore.signal()
        }
    }
    
    // This `for` loop iterates over each element as it's
    // received from the queue. Because we only have two elements,
    // the iteration terminates after receiving the 2 elements.
    for _ in 0..<values.count {
        semaphore.wait()
    }
}

main()
$ swift range-over-channels.swift
one
two

This example shows how to simulate channel-like behavior in Swift using Grand Central Dispatch (GCD) and semaphores. While Swift doesn’t have built-in channels like some other languages, we can achieve similar functionality using these concurrency primitives.

In this code:

  1. We create a dispatch queue and a semaphore.
  2. We use an array to hold our values, simulating a channel with two elements.
  3. We dispatch an asynchronous task that iterates over the values, printing each one and signaling the semaphore.
  4. In the main thread, we wait on the semaphore for each value, effectively “receiving” from our simulated channel.

This approach demonstrates how to achieve controlled, sequential processing of asynchronous events in Swift, which is conceptually similar to ranging over a channel in other languages.