Combine

Implementing a one-way sync strategy with Core Data, URLSession and Combine

Published on: August 24, 2020

A common use of a Core Data store is to cache data from a remote resource locally to support offline functionality of an app. There are multiple ways to implement a caching mechanism and many of them don't involve Core Data. For example, you could simply fetch a JSON file from a server and store the contents of that JSON file on disk. A downside of fetching a full data set every time is that you risk using a lot of bandwidth, especially if your data set is large, or if your data set is expected to grow over time....

Read more...

Implementing an infinite scrolling list with SwiftUI and Combine

Published on: June 29, 2020

Tons of apps that we build feature lists. Sometimes we build lists of settings, lists of todo items, lists of our favorite pictures, lists of tweets, and many other things. Some of these lists could scroll almost endlessly. Think of a Twitter timeline, a Facebook feed or a list of posts on Reddit. You might argue that knowing how to build a list that scrolls infinitely and fetches new content whenever a user reaches the end of the list is an essential skill of any iOS developer. That's why as one of my first posts that covers SwiftUI I wanted...

Read more...

Using custom publishers to drive SwiftUI views

Published on: June 23, 2020

In SwiftUI, views can be driven by an @Published property that's part of an ObservableObject. If you've used SwiftUI and @Published before, following code should look somewhat familiar to you: class DataSource: ObservableObject { @Published var names = [String]() } struct NamesList: View { @ObservedObject var dataSource: DataSource var body: some View { List(dataSource.names, id: \.self) { name in Text(name) } } } Whenever the DataSource object's names array changes, NamesList will be automatically redrawn. That's great. Now imagine that our list of names is retrieved through the network somehow and we want to load the list of names in...

Read more...

Ignore first number of elements from a publisher in Combine

Published on: June 19, 2020

If you have a Combine publisher and you want to ignore the first n elements that are published by that publisher, you can use the dropFirst(_:) operator. This operator will swallow any values emitted until the threshold you specify is reached. For example, dropFirst(1) will ignore the first emitted value from a publisher: [1, 2, 3].publisher .dropFirst(1) .sink(receiveValue: { value in print(value) // 2 and 3 are printed }) For more information about dropFirst and several variations of drop like drop(while:) and drop(untilOutputFrom:) you can refer to Apple's documentation.

Read more...

Recursively execute a paginated network call with Combine

Published on: June 15, 2020

Last week, my attention was caught by a question that Dennis Parussini asked on Twitter. Dennis wanted to recursively make calls to a paginated API to load all pages of data before rendering UI. Since I love Combine and interesting problems I immediately started thinking about ways to achieve this using a nice, clean API. And then I realized that this is a non-trivial task that was worth exploring. In this week's post, I would like to share my thought process and solution with you, hoping you'll learn something new about Combine in the process. Understanding the problem and setting...

Read more...

What’s the difference between catch and replaceError in Combine?

Published on: May 29, 2020

There are several ways to handle errors in Combine. Most commonly you will either use catch or replaceError if you want to implement a mechanism that allows you to recover from an error. For example, catch is useful if you want to retry a network operation with a delay. The catch and replaceError operators look very similar at first glance. They are both executed when an error occurs in your pipeline, and they allow you to recover from an error. However, their purposes are very different. When to use catch The catch operator is used if you want to inspect...

Read more...

Retrying a network request with a delay in Combine

Published on: May 25, 2020

Combine comes with a handy retry operator that allows developers to retry an operation that failed. This is most typically used to retry a failed network request. As soon as the network request fails, the retry operator will resubscribe to the DataTaskPublisher, kicking off a new request hoping that the request will succeed this time. When you use retry, you can specify the number of times you want to retry the operation to avoid endlessly retrying a network request that will never succeed. While this is great in some scenarios, there are also cases where this behavior is not what...

Read more...

Getting started with testing your Combine code

Published on: May 11, 2020

A question that often comes up when folks get into learning Combine is "how do I test code that uses Combine?". In this week's post, I will briefly explain the basics of testing Combine code. I will assume that you already know the basics of testing and Combine. If you're just getting started with both topics or would like a refresher I can recommend that you take a look at the following resources: My series of posts on testing My series of posts on Combine My Practical Combine book if you want to learn a lot more about Combine, and...

Read more...

Changing a publisher’s Failure type in Combine

Published on: April 15, 2020

One of Combine's somewhat painful to work with features is its error mechanism. In Combine, publishers have an Output type and a Failure type. The Output represents the values that a publisher can emit, the Failure represents the errors that a publisher can emit. This is really convenient because you know exactly what to expect from a publisher you subscribe to. But what happens when you have a slightly more complicated setup? What happens if you want to transform a publisher's output into a new publisher but the errors of the old and new publishers don't line up? The other...

Read more...

Profiling and debugging your Combine code with Timelane

Published on: March 16, 2020

When we write code, we write bugs. It's one of the laws of the universe that we can't seem to escape. The tools we have to discover, analyze and fix these bugs are extremely important because without good debugging tools we'd be poking at a black box until we kind of figure out what might be happening in our code. Debugging synchronous code is hard enough already, but once your code involves several streams of asynchronous work debugging becomes much harder because asynchronous code can be inherently hard to keep track of. Combine code is asynchronous by nature. When you...

Read more...