API Calls with iOS Combine
Mastering API Calls in iOS Using Combine Framework with Swift
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!