Combine framework for reactive programming

Sofia Martinez Jan 2026
2 tabs
import Foundation
import Combine

class NetworkService {
    private let baseURL = "https://api.example.com"
    private var cancellables = Set<AnyCancellable>()

    func fetchPosts() -> AnyPublisher<[Post], Error> {
        guard let url = URL(string: "\(baseURL)/posts") else {
            return Fail(error: URLError(.badURL))
                .eraseToAnyPublisher()
        }

        return URLSession.shared.dataTaskPublisher(for: url)
            .map(\.data)
            .decode(type: PostsResponse.self, decoder: JSONDecoder())
            .map { $0.posts }
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }

    func searchPosts(query: String) -> AnyPublisher<[Post], Error> {
        guard let url = URL(string: "\(baseURL)/posts/search?q=\(query)") else {
            return Fail(error: URLError(.badURL))
                .eraseToAnyPublisher()
        }

        return URLSession.shared.dataTaskPublisher(for: url)
            .retry(3)
            .map(\.data)
            .decode(type: [Post].self, decoder: JSONDecoder())
            .catch { error -> AnyPublisher<[Post], Error> in
                print("Error fetching posts: \(error)")
                return Just([])
                    .setFailureType(to: Error.self)
                    .eraseToAnyPublisher()
            }
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }
}

struct PostsResponse: Decodable {
    let posts: [Post]
}

struct Post: Decodable, Identifiable {
    let id: Int
    let title: String
    let body: String
    let authorId: Int
}
2 files · swift Explain with highlit

Combine provides a declarative Swift API for processing values over time, perfect for handling async events like network requests, user input, and timers. Publishers emit sequences of values, and subscribers receive them. Operators transform, filter, and combine streams. I use URLSession.dataTaskPublisher for network calls, chaining operators like map, decode, and catch for transformation and error handling. The @Published property wrapper creates publishers automatically. Combine's sink and assign subscribers connect publishers to UI or state. Cancellables manage subscription lifecycles. This reactive approach eliminates callback hell and makes async code linear and composable.