Combine

What exactly is a Combine AnyCancellable?

Published on: August 24, 2021

If you've worked with Combine at all in your applications you'll know what it means when I tell you that you should always retain your cancellables. Cancellables are an important part of working with Combine, similar to how disposables are an important part of working with RxSwift. For example, you might have built a publisher that wraps CLLocationManagerDelegate and exposes the user's current location with a currentLocation publisher that's a CurrentValueSubject<CLLocation, Never>. If you subscribe to this publisher it might look a bit like this: struct ViewModel { let locationProvider: LocationProvider var cancellables = Set<AnyCancellable>() init(locationProvider: LocationProvider) { self.locationProvider =...

Read more...

Thoughts on Combine in an async/await world

Published on: June 8, 2021

When Apple announced their own Functional Reactive Programming framework at WWDC 2019 I was super excited. Finally, a simplified, easy to use framework that we could use to dip our toes in FRP. What made it even better is that SwiftUI makes heavy use of Combine, which means that Apple had to buy in to the technology themselves. This made it seem unlikely that Apple would abandon the technology any time soon. Then WWDC 2020 came around and there weren’t any meaningful changes to Combine. It was hardly even mentioned in the sessions. To me, this was a signal that...

Read more...

Observing the result of saving a background managed object context with Combine

Published on: December 7, 2020

I love posts where I get to put write about two of my favorite frameworks at the moment; Combine and Core Data. When you're working with Core Data, it's common to perform save operations asynchronously using a background context. You could even perform an asynchronous save on the main managed object context. Consider the following method that I added to an object that I wrote called StorageProvider: public extension StorageProvider { func addTask(name: String, description: String, nextDueDate: Date, frequency: Int, frequencyType: HouseHoldTask.FrequencyType) { persistentContainer.performBackgroundTask { context in let task = HouseHoldTask(context: context) task.name = name task.taskDescription = description task.nextDueDate =...

Read more...

Building a concurrency-proof token refresh flow in Combine

Published on: November 9, 2020

Refreshing access tokens is a common task for many apps that use OAuth or other authentication mechanisms. No matter what your authentication mechanism is, your tokens will expire (eventually) and you'll need to refresh them using a refresh token. Frameworks like RxSwift and Combine provide convenient ways to build pipelines that perform transformation after transformation on a succesful network response, allowing you to grab Data, manipulate and transform it to an instance of a model object or anything else. Programming the not-so-happy path where you need to refresh a token is not as simple. Especially because in an ideal world...

Read more...

Building a simple remote configuration loader for your apps

Published on: October 26, 2020

Remote configuration is a common practice in almost every app I have worked on. Sometimes these configurations can be large and the implications of a configuration change can be far-reaching while other times a configuration is used to change the number of items shown in a list, or to enable or disable certain features. You can even use remote configuration to set up your networking layer. For example by setting certain headers on a request, providing endpoints for your remote data, and more. In this week's post I will not go into detail about every possible use case that you...

Read more...

Observing changes to managed objects across contexts with Combine

Published on: October 12, 2020

A common pattern in Core Data is to fetch objects and show them in your UI using one managed object context, and then use another context to update, insert or delete managed objects. There are several ways for you to update your UI in response to these changes, for example by using an NSFetchedResultsController. I wrote about doing this in a SwiftUI app in an earlier post. In this week's post I will show you a useful technique that allows you to observe specific managed objects across different contexts so you can easily update your UI when, for example, that...

Read more...

Configuring error types when using flatMap in Combine

Published on: September 14, 2020

When you're using Combine for an app that has iOS 13 as its minimum deployment target, you have likely run into problems when you tried to apply a flatMap to certain publishers in Xcode 12. To be specific, you have probably seen the following error message: flatMap(maxPublishers:_:) is only available in iOS 14.0 or newer. When I first encountered this error I was somewhat stumped. Surely we had flatMap in iOS 13 too! If you've encountered this error and thought the same, let me reassure you. You're right. We had flatMap in iOS 13 too. We just gained new flavors...

Read more...

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...