Skip to content

Apps Dissected Posts

Save that sink! A simple solution to a common Combine problem

So you’re starting to work with Combine, because Apple is finally jumping on the reactive programming bandwagon (yay!). So you build your first Combine workflow, and it looks something like this:

And then you try and use it, and instead of getting the data response you were expecting, you get an error:

Cancelled? Why did my request get cancelled?

The key in the above code is that you missed something important. I made this exact same mistake when I started using Combine, and sadly I don’t think it will be the last time, because it is just that easy to miss. Let’s talk about the solution, and why you get the error when you don’t do it.

Restoring your sanity reading JSON into Codables

Integrating your app with APIs means you’re going to be dealing with parsing JSON in data objects you can use nicely. iOS provides the Codable protocol to do just that thing, but once you start trying to map JSON to that well-formed protocol, that’s when things fall apart.

JSON doesn’t have standard schemas (at least none that were ever seriously adopted), so you’re stuck with reading documentation like this for the details:

😒 Great, that’s useful… One example response, no field descriptions, types, anything. (And before you ask, this is the GitHub API documentation, so not even large organizations are immune to this problem.)

So you code your app off of these examples, then when you try and use it in the wild, you get:

I followed their documentation, and it didn’t work. How the heck am I ever going to figure out how to make this API JSON into a nice, easy to use Swift struct?!

Thankfully, there are some tricks — and one tool — you can use to make your job a lot easier. We’ll start by deciphering those error messages above, and how to figure out what error they are trying to point out. Then we’ll cover a procedure I like to use whenever I encounter one of these errors to fix them, and even use to avoid these errors in the first place. Let’s dive in.

I create a batch of CloudKit records, but when I try to sort them by date, they’re all jumbled?

If your app stores user data in a database, there are a number of occasions where you may need to make changes to multiple objects at once. The most likely scenario is you are loading the initial database state for a new user as part of the onboarding process, but it may also come at times where a user modifies a bunch of records at once, or an app upgrade requires the app to modify those values somehow.

If you’re using CloudKit as your database, you follow the common advice: per Apple’s recommendation, and for the sake of performance, you want to make as few of these CloudKit operations as possible, so you create or modify records in one batch, using a CKModifyRecordsOperation.

But then if you want to sort these records in order of when they were created, or last modified, using a creationDate or modificationDate NSSortDescriptor, those records are out of order. You inserted them 1-2-3-4-5, but you get 2-4-3-5-1.

Even worse, every time you ask for those records, the order is different. So the next time, it’s 3-1-2-5-4.

I added the records in the order I wanted them; why is CloudKit messing up the order?

There are two things happening that cause this behavior: one of them is specific to CloudKit’s batch creation and modification, and one of them is common behavior across many database systems, including CloudKit. We’ll dig into both issues, and then talk about a couple of ways you can make your records sort by date cleanly.

Keep control of your modal presentation in iOS 13

You hear about the large features in new major version iOS updates, but it’s often the small changes that cause you headaches: the places where Apple has deprecated functionality or changed defaults that you’ve been relying on for years.

iOS 13 has one of those major changes with respect to how modal ViewControllers are displayed. They are now displayed in a card format by default. That itself is not overly problematic, but as part of that change, it also enables the user to dismiss a modal by swiping down from the top of the screen.

If your app expects that it will have full control over being dismissed, this could be a major problem. Suddenly, your login form that you are displaying with a modal can just be swiped away, leading to unexpected behavior: crashes, unpopulated screens, access to things a user shouldn’t have access to.

Building with the old iOS 12 SDK is an option — for a while. How do you restore that classic functionality, making your modals fullscreen by default, with full control over how they are dismissed? Thankfully, it is not a hard fix, but the fix depends on how you are presenting your ViewController. Let’s cover all of the different fixes now.

4 things you can do *right now* to be ready for SwiftUI and Combine

Many of us were excited about all the new frameworks at WWDC: SwiftUI and Combine being the biggest ones. You were probably all ready to start using them in your app, until you opened up the documentation and saw this:

And you felt at least one of these feelings:

😡 😭 🙄

You knew at that point, that even with the usual new iOS version adoption curve, unless you’re looking at sacrificing a significant portion of your user base, you’re looking at adopting all these new features in Spring 2020, at the earliest. If your app needs to support older OS versions for a longer period, it could be even longer.

Bummer.

You can’t fix your users: they upgrade whenever they do (but thank Apple for new emoji ever year). But you also don’t need to sit on the sidelines and wait until those features are widely available to start implementing them. There are some things you can do while you’re waiting for your users to catch up, so that you’ll be ready to deliver apps based on these great new frameworks. You can even do some of this work now, while those betas are less than stable. Here are a few things to think about.