API Calls with iOS Combine

Mastering API Calls in iOS Using Combine Framework with Swift

Sachin Goswami
3 min readOct 8, 2023

In the world of iOS app development, handling asynchronous tasks like making API calls is a common requirement. Traditionally, developers used callbacks or completion handlers to manage these tasks. However, with the introduction of Combine in iOS 13, there’s a more elegant and functional way to handle asynchronous operations.

Combine is a framework that provides a declarative Swift API for processing values over time. It allows you to work with asynchronous data streams, making it a perfect fit for handling API calls. In this blog post, we’ll explore how to make API calls using Combine in iOS.

Prerequisites

Before we dive into the code, make sure you have a basic understanding of Swift and Xcode. You should also have Xcode installed on your Mac.

Setting up a Sample Project

Let’s start by creating a new iOS project in Xcode. Choose the “Single View App” template and name your project “CombineAPIDemo.”

Importing Combine

Combine is a built-in framework in iOS, so there’s no need to add any external dependencies. Just make sure to import Combine in your Swift files where you’ll be using it.swiftCopy code

import Combine

Creating a Model

For this demonstration, let’s assume we’re building an app that fetches a list of todos from a REST API. We’ll need a model to represent a todo item. Create a Swift file named Todo.swift and define the model like this:swiftCopy code

struct Todo: Decodable {
let id: Int
let title: String
let completed: Bool
}

Building the API Service

Next, let’s create a service to make API requests. In a real-world scenario, you might want to use a networking library like Alamofire, but for simplicity, we’ll use the built-in URLSession. Create a Swift file named TodoService.swift and define a class for the service:

import Foundation
import Combine
class TodoService {
private let baseURL = URL(string: "https://jsonplaceholder.typicode.com/todos")!
func fetchTodos() -> AnyPublisher<[Todo], Error> {
URLSession.shared.dataTaskPublisher(for: baseURL)
.map(\.data)
.decode(type: [Todo].self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
}

In this code, we define a TodoService class with a fetchTodos method that returns a Combine AnyPublisher. It uses URLSession to make an API request, decode the JSON response into an array of Todo objects, and erase the type to AnyPublisher.

Fetching Todos in the View Model

Now, let’s move to our view model. Create a Swift file named TodoViewModel.swift:

import Foundation
import Combine
class TodoViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
private let todoService = TodoService()
@Published var todos: [Todo] = [] func fetchTodos() {
todoService.fetchTodos()
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { _ in }) { todos in
self.todos = todos
}
.store(in: &cancellables)
}
}

In this view model, we define a fetchTodos method that calls the fetchTodos method of our TodoService. We use the @Published property wrapper to create a published property called todos that will automatically update our UI when the data changes. We also use receive(on:) to ensure that updates are received on the main thread for UI updates.

Displaying Data in the View

Finally, let’s create a SwiftUI view to display the list of todos. Create a Swift file named TodoListView.swift:

import SwiftUI
struct TodoListView: View {
@ObservedObject var viewModel = TodoViewModel()
var body: some View {
NavigationView {
List(viewModel.todos, id: \.id) { todo in
Text(todo.title)
}
.onAppear {
viewModel.fetchTodos()
}
.navigationBarTitle("Todos")
}
}
}
struct TodoListView_Previews: PreviewProvider {
static var previews: some View {
TodoListView()
}
}

In this view, we create an ObservedObject called viewModel of type TodoViewModel to observe changes in the todos property. We use a List to display the list of todos and call viewModel.fetchTodos() in the onAppear modifier to fetch data when the view appears.

Wrapping Up

Combine is a powerful framework for handling asynchronous operations like API calls in iOS apps. It provides a declarative and functional way to work with asynchronous data streams, making your code more readable and maintainable.

In this blog post, we’ve walked through the process of setting up a basic project, creating a model, building an API service, and fetching data in a view model using Combine. With these fundamentals in place, you can build more complex and responsive iOS apps that make use of Combine for handling API calls and other asynchronous tasks. Happy coding!

--

--