Closing Channels in Swift

Here’s the translated Swift code and explanation in Markdown format suitable for Hugo:

Our first example demonstrates how to close channels in Swift. Closing a channel indicates that no more values will be sent on it. This can be useful to communicate completion to the channel’s receivers.

import Foundation

// In this example we'll use a `jobs` channel to communicate work to be done from the main thread
// to a worker thread. When we have no more jobs for the worker we'll close the `jobs` channel.
func main() {
    let jobs = DispatchQueue(label: "jobs")
    let done = DispatchSemaphore(value: 0)
    
    // Here's the worker closure. It repeatedly receives from `jobs` using a dispatch work item.
    // We use a boolean flag `more` to indicate if there are more jobs to process.
    // We use this to notify on `done` when we've worked all our jobs.
    jobs.async {
        var more = true
        while more {
            jobs.async(flags: .barrier) {
                if let job = jobs.sync(execute: { () -> Int? in
                    // Simulating receiving a job
                    return Int.random(in: 1...3)
                }) {
                    print("received job", job)
                } else {
                    print("received all jobs")
                    more = false
                    done.signal()
                }
            }
        }
    }
    
    // This sends 3 jobs to the worker over the `jobs` queue, then marks it as complete.
    for j in 1...3 {
        jobs.async {
            print("sent job", j)
        }
    }
    jobs.async(flags: .barrier) {
        print("sent all jobs")
    }
    
    // We await the worker using the synchronization approach.
    done.wait()
    
    // In Swift, we don't have a direct equivalent to reading from a closed channel.
    // Instead, we can use a boolean flag or optional to indicate completion.
    let moreJobs = false
    print("received more jobs:", moreJobs)
}

main()

To run the program, save it as ClosingChannels.swift and use swift command:

$ swift ClosingChannels.swift
sent job 1
received job 2
sent job 2
received job 1
sent job 3
received job 3
sent all jobs
received all jobs
received more jobs: false

This example demonstrates 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.

The concept of closed channels leads naturally to our next example: iterating over dispatch queues or collections in Swift.