Closures Vs. Combine Vs. Async Await

Closures Vs. Combine Vs. Async Await

Introduction

No alt text provided for this image
Design Credit: Joel Colletti, Lead UI/UX Designer @ InRhythm

There are three methods of asynchronous coding in Swift: Closures (i.e. completion handlers), Combine, and Async/Await.?

Closures are a fundamental feature of Swift that allow developers to define self-contained blocks of functionality, while Combine provides a modern way to handle asynchronous events and data streams. Async/Await is a new feature that makes it easier to write asynchronous code that looks and feels like synchronous code, improving the readability and maintainability of Swift code.

  • Closures – Introduced in Swift 2.0, WWDC 2015
  • Combine – iOS 13 and macOS Catalina in 2019
  • Async/Await – Swift 5.5 WWDC 2021

Asynchronous Coding Methods

No alt text provided for this image

Closures

No alt text provided for this image

In Swift programming, closures are a powerful and versatile feature that allow you to capture and store functionality for later use. A closure is a self-contained block of code that you can pass around and execute at a later time, similar to a function or method.

A common use case for closures is handling asynchronous operations, such as network requests or animations. Defining a closure that executes when the operation completes helps you to keep your code organized and avoid callback functions.

You can use closures in Swift in different ways:

  • As a function argument: Pass the closure as a function argument to define a custom behavior tailored to a specific use case.
  • As a function return value: As the return value of a function, you can create functions that generate other functions.
  • As a variable: You can assign a closure to a variable for later use.

Closures can capture and retain references to values outside of their own scope which allows you to define closures that can access and modify variables defined outside of their own function or method.?

Combine

No alt text provided for this image

Combine is a powerful framework that allows developers to handle asynchronous events and data streams in a more intuitive and functional way. The Combine framework provides a declarative way to define and manipulate data streams using a set of operators that can transform, filter, and combine data in various ways.

Key use cases for the Combine framework include:

  1. Handling asynchronous events: Combine allows developers to handle asynchronous events, such as network requests or user input, in a more elegant and concise way than traditional callback-based APIs
  2. Managing data streams: Combine provides a unified way to manage data streams from various sources, such as user input, network requests, and local storage
  3. Composing reactive UI: Combine can be used to create reactive UI, where the UI updates automatically in response to changes in the underlying data
  4. Testing: Combine’s declarative syntax makes it easy to write unit tests for asynchronous code

The key building blocks of Combine are?publishers?and?subscribers. Publishers are objects that emit a stream of values over time, while subscribers consume these values and perform some action in response. Publishers can be transformed, combined, and filtered using various operators to create complex data pipelines.

In summary, the Combine framework provides a powerful way to handle asynchronous events and data streams in Swift programming.

Async/Await

No alt text provided for this image

Async/Await provides a more intuitive and concise way to write asynchronous code. With Async/Await, developers can write asynchronous code that looks and feels like synchronous code, which makes it easier to read, write, and maintain.

Previously, developers used callbacks or closures to handle the results of asynchronous operations which often lead to complex and difficult-to-read code, as well as potential issues with callback hell and race conditions.

With Async/Await, developers can use familiar keywords like Await and Async to write asynchronous code, which allows them to pause the execution of a function until a result is available, without blocking the main thread. This makes it easier to write code that is both asynchronous and easy to understand.

For example, this code uses Async/Await to perform a network request:

No alt text provided for this image

In the example, fetchUser() function is marked as Async, indicating that it is an asynchronous function. Inside the function, the await keyword is used to wait for the result of the network request, without blocking the main thread. The result is then returned as a User object.

Overall, Async/Await is a powerful new feature that makes it easier to write asynchronous code in Swift, while also improving readability and maintainability.

Comparison

No alt text provided for this image

Features

Note that while Closures and Combine are both used for handling asynchronous operations, they operate at different levels of abstraction. Closures are used for defining code blocks with captured values, whereas Combine is a reactive programming framework that provides a unified way to manage asynchronous data streams. Async/Await, on the other hand, is a language-level feature that simplifies the process of writing asynchronous code by allowing developers to write asynchronous code that looks and feels like synchronous code.

No alt text provided for this image
No alt text provided for this image

Side-By-Side Code Function Definition

No alt text provided for this image

The?Closure?example code is fairly complex and a developer would need to examine the entire code block to be certain of its operation.

In the?Combine?block, the code is slightly less complex. The addition of?.map,?.decode, and?.mapError?help make it more understandable.

In the?Async/Await?code block, not only is there less code, it is also easier to understand what the code does: Set the path, create the request, make the call, and send the data back.

The code is still doing all of the?“heavy lifting”?for asynchronous coding, but it doesn’t?LOOK?as though it is doing the heavy lifting.

Side-By-Side Function Usage

No alt text provided for this image

The comparison of the three approaches?really?becomes clear when you look at the synchronizing calls inside of the same function.

As you can see, the result of the first call (i.e. getting a list of food by name) must come back to complete the second call (i.e. getting a list of foods that have the same “category” as the initial result).

Managing the response from the initial call is rather difficult, especially if we need to obtain sensible information about an error when something does go wrong. That difficulty only increases when we become reliant not only on a successful response, but also rely on the data as a result of that second response to power the second request.

Resources

Combine

Async Await

This article was originally published as a part of the Propel Spring Quarterly Summit series on the InRhythm blog.

This newsletter was curated by InRhythm's Senior Technical Writer,?Mike Adams. Thoughts or questions? Sound off in the comments section below.

Yuri Pikha

Angular Developer

10 个月

Comparison doesn't do justice to Combine. Why would you catch smth that is realistically should be considered normal flow, i.e. empty search result. Anyway you can create observables for uncategorized and categorized results, latter subscribing to former, then use CombineLatest on them both or use them as published vars in viewmodel.

回复
Ted Parton

Technology Enthusiast in the 615

1 年

Thank you for the great write up Mike Adams

要查看或添加评论,请登录

InRhythm的更多文章

社区洞察

其他会员也浏览了