Instruction 2

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

Protocol-Oriented Programming

Protocol-Oriented Programming is a design pattern that enables you to abstract implementation details across various components of your app. It’s commonly used to separate concerns in your code, such as decoupling UI logic from data logic.

For example, you might have a View to display a list of books. The view shouldn’t care about how the items are retrieved or whether it needs to make specific API calls or database queries to get the data. Instead, you can define a protocol:

protocol BookRepository {
    func getBooks() async throws  -> [Book]
    func createBook(_ book: Book) async throws
}

This protocol outlines a few functions for retrieving and creating books Note how there are no implementation details; that’s decided by the implementer of the protocol. The view simply uses the protocol’s API to perform the actions it needs to.

This also makes it very easy to change the implementation; for example, you can easily switch between using SwiftData and an API or even some mocked data for testing.

You could then provide an implementation of this protocol that uses an API:

// 1
struct APIBookRepository: BookRepository {
    // Define URLs...

    // 2
    func getBooks() async throws -> [Book] {
        // 3
        let (data, _) = try await URLSession.shared.data(from: booksURL)
        return try JSONDecoder().decode([Book].self, from: data)
    }
    
    // 4
    func createBook(_ book: Book) async throws {
        // 5
        let data = try JSONEncoder().encode(book)
        // 6
        var request = URLRequest(url: createBookURL)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = data
        // 7
        _ = try await URLSession.shared.data(for: request)
    }
}

Here’s what the code does:

  1. Defines a new type that conforms to BookRepository to retrieve books from an API.
  2. Implements getBooks() to retrieve books from the API.
  3. Uses URLSession to retrieve the data from the API and decode the response to an array of Books. The function must return this information.
  4. Implements createBook(_:) to create a new book.
  5. Encodes the book to JSON.
  6. Creates a URLRequest to send to the API. Sets the method, header and body parameters for sending the new book data to the API.
  7. Sends the request to the API using URLSession.

Note: For most SwiftUI apps, the responsibility of retrieving data is usually handled by a ViewModel rather than the View directly. The View’s sole responsibility is to display the data it receives. For more information, check out Advanced iOS App Architecture and other related Kodeco articles on the Model-View-ViewModel (MVVM) pattern.

See forum comments
Download course materials from Github
Previous: Demo 1 Next: Demo 2