Skip to content

Apps Dissected Posts

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.

Catch SwiftUI model updates from bad threads before they crash your app

It hasn’t yet been reflected in the official SwiftUI documentation (yay, betas), but the WWDC presentations and further guidance from Apple engineers have made it very clear about one point of SwiftUI: as with UIKit, you must send SwiftUI updates only from the main thread. The more things change…

The bad thing about this is that if you don’t make your updates on the main thread, you get away with it.

Most of the time.

The reality: updating the UI outside the main thread — in UIKit and in the newer SwiftUI — is going to be a source of hard to debug bugs, possible race conditions when updates are made to the UI, and at worst, app crashes.

Your BindableObjects may have many attributes, all that require you to do a willChange.send(). With so many places where your asynchronous code may need to trigger an update to your Views, what can you do to catch those missed main thread migrations before they become headaches? Xcode can save your sanity with its built-in Main Thread Checker debug functionality. Let’s walk through a basic example.

Order your Core Data entities the right way for maximum speed

One of the earliest things you learn about Core Data is that it doesn’t support ordered entities out of the box. Sometimes you can have an ordered relationship, but the minute you try and move that database to iCloud, you find that ordered relationships aren’t supported. Long story short: if you want to order your entities, then you need to create an index attribute that allows you to sort your entities yourself.

So you do the natural thing: create your index attribute as an Int, and then assign each in order: 1, 2, 3…

This is fine if the data doesn’t change, but if this is data the user can add to and reorder, what if they want to move element 3 between 1 and 2? It means you need to change 2 entities in addition to adding the new one. What if there are 500 entities, and the user wants to insert a new first element. 500 entities to change because the user moved a single entity?!

There must be a way to insert and reorder IDs that avoids all of this rewriting, right?

Thankfully there are a couple of techniques you can use that will almost completely eliminate the need to rewrite a huge number of entities every time you need to insert or rearrange entities. Let’s talk about them now.