Swift Combine Series: Part 2 — Networking with Combine

Vikram Kumar
3 min readJan 25, 2025

--

Welcome to Part 2 of our Swift Combine journey! If Part 1 got your Combine engines revving, this part will take you on a scenic drive through the networking highways. Grab your coffee (or tea, no judgment), and let’s unravel how Combine simplifies the art of fetching data and making API calls in Swift.

Photo by Christian Wiediger on Unsplash

“Reactive programming isn’t magic — it’s just beautifully orchestrated logic.” Combine makes this orchestration feel like a symphony.

Why Combine for Networking?

Networking with Combine is like swapping a rusty old bicycle for a shiny new car. It’s sleek, modern, and gets the job done with style. Forget the callback pyramid of doom or juggling DispatchQueues — Combine handles asynchronicity like a pro.

  • Declarative Syntax: Say goodbye to tangled code; write what you mean.
  • Error Handling: Easily manage those pesky errors.
  • Chaining: Transform and filter your data streams with elegance.

Making Your First Network Request

Let’s fetch some JSON data! In this example, we’ll use a public API to retrieve a list of posts.

Example 1: Fetching Posts

import Combine
import Foundation

// Define the model
struct Post: Decodable {
let id: Int
let title: String
let body: String
}

// Create a URL
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")!

// Create a publisher
let cancellable = URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data } // Extract data
.decode(type: [Post].self, decoder: JSONDecoder()) // Decode JSON
.receive(on: DispatchQueue.main) // Update UI on the main thread
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("Fetch completed successfully!")
case .failure(let error):
print("Error fetching posts: \(error)")
}
}, receiveValue: { posts in
print("Received posts: \(posts)")
})

Note: The cancellable instance must be stored outside the function body, such as in a property or an array, to prevent the subscription from being canceled prematurely. If it goes out of scope, the Combine framework will terminate the subscription before it completes its task.

Output:

Fetch completed successfully!
Received posts: [Post(id: 1, title: "Sample", body: "..."), ...]

Error Handling Like a Pro

Let’s see how Combine lets you handle errors gracefully.

Example 2: Handling Errors

let errorHandlingCancellable = URLSession.shared.dataTaskPublisher(for: url)
.tryMap { result -> Data in
guard let response = result.response as? HTTPURLResponse, response.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return result.data
}
.decode(type: [Post].self, decoder: JSONDecoder())
.catch { error in
Just([Post(id: 0, title: "Error", body: "Could not fetch data")]) // Fallback data
}
.sink(receiveValue: { posts in
print("Posts: \(posts)")
})

Transforming Data Streams

Combine shines when it comes to transforming data. Let’s see an example of fetching posts and transforming the titles to uppercase.

Example 3: Transforming Titles

let transformingCancellable = URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data }
.decode(type: [Post].self, decoder: JSONDecoder())
.map { posts in
posts.map { $0.title.uppercased() }
}
.sink(receiveCompletion: { _ in }, receiveValue: { titles in
print("Transformed Titles: \(titles)")
})

Output:

Transformed Titles: ["LOREM IPSUM", "DOLOR SIT AMET", ...]

Practical Tips

  1. Debugging Requests: Use the .print() operator to inspect your data stream:
URLSession.shared.dataTaskPublisher(for: url)
.print()
.sink { ... }
  1. Caching Responses: Combine beautifully integrates with URLCache for caching network responses.
  2. Chaining Requests: Need to make sequential API calls? Combine lets you chain publishers seamlessly.

What’s Next?

In the next part of this series, we’ll dive into Combine and SwiftUI, exploring how to bind data streams directly to your UI. If you think Combine is fun now, just wait until you see it in action with SwiftUI. Until then, happy coding!

Checkout Part 1:

--

--

Vikram Kumar
Vikram Kumar

Written by Vikram Kumar

I am Vikram, a Senior iOS Developer at Matellio Inc. focused on writing clean and efficient code. Complex problem-solver with an analytical and driven mindset.

No responses yet