0Pricing
Swift Academy · Lesson

Transforming and Combining Streams

Use flatMap, merge, combineLatest, and zip.

Transforming and Combining Streams is a free Swift Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Working with Streams

In Combine, a publisher emits a stream of values over time. The real power comes from operators that transform and combine these streams into new ones.

This lesson covers the most important transforming and combining operators: flatMap, merge, combineLatest, and zip.

map vs flatMap

map transforms each value into another value. flatMap goes further — it transforms each value into a new publisher and flattens the results into a single stream.

Use flatMap when each input should trigger another async operation.

flatMap in Action

Here a stream of user IDs is mapped to a stream of network requests, flattened into one stream of users.

userIdPublisher
    .flatMap { id in
        apiClient.fetchUser(id: id)
    }
    .sink { user in
        print("Loaded", user.name)
    }
    .store(in: &cancellables)

Controlling flatMap Concurrency

By default flatMap subscribes to all inner publishers at once. You can cap concurrency with maxPublishers to avoid flooding a server.

idsPublisher
    .flatMap(maxPublishers: .max(2)) { id in
        apiClient.fetchUser(id: id)
    }
    .sink { print($0) }
    .store(in: &cancellables)

merge

merge interleaves values from multiple publishers of the same type into one stream, emitting each value as soon as it arrives.

let combined = buttonTapA
    .merge(with: buttonTapB)

combined
    .sink { print("A tap from either button") }
    .store(in: &cancellables)

combineLatest

combineLatest emits whenever any input publisher emits, pairing the newest value from each. It is perfect for form validation where several fields must all be considered.

usernamePublisher
    .combineLatest(passwordPublisher)
    .map { name, pass in
        !name.isEmpty && pass.count >= 8
    }
    .sink { isValid in
        print("Form valid:", isValid)
    }
    .store(in: &cancellables)

combineLatest Behavior

Note: combineLatest emits nothing until every input has produced at least one value. After that, each new emission from any input fires the combined output with the latest of the others.

zip

zip pairs values by index: the first of A with the first of B, the second with the second, and so on. It waits for both sides to have a value at each position.

let names = ["Ann", "Bob", "Cy"].publisher
let ages = [30, 25, 41].publisher

names
    .zip(ages)
    .sink { name, age in
        print(name, "is", age)
    }
    .store(in: &cancellables)

combineLatest vs zip

The two are easy to confuse:

  • combineLatest — fires on any emission, uses newest of each
  • zip — fires only on matched pairs by index

Use combineLatest for live state; use zip to align parallel results one-to-one.

Combining for Parallel Work

zip shines when running independent requests in parallel and waiting for all of them.

fetchProfile
    .zip(fetchSettings)
    .sink { profile, settings in
        print("Both loaded")
    }
    .store(in: &cancellables)

Chaining Operators

Real pipelines chain several operators together to express complex async flows declaratively.

searchTextPublisher
    .removeDuplicates()
    .flatMap { query in
        apiClient.search(query)
    }
    .map { results in
        results.prefix(10)
    }
    .sink { print($0) }
    .store(in: &cancellables)

Quick Check

Test your operator knowledge.

Recap

You learned to transform and combine streams:

  • flatMap — value to publisher, flattened
  • merge — interleave same-typed streams
  • combineLatest — newest of each, fires on any
  • zip — index-matched pairs

These operators let you compose complex async logic declaratively.

Frequently asked questions

Is the “Transforming and Combining Streams” lesson free?

Yes — the full text of “Transforming and Combining Streams” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.

What will I learn in “Transforming and Combining Streams”?

Use flatMap, merge, combineLatest, and zip. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Swift Academy?

No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Transforming and Combining Streams” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Swift Academy lesson?

Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Transforming and Combining Streams
  2. Schedulers and Threading
  3. Error Handling Operators
  4. Custom Publishers and Subscribers
← Back to Swift Academy