Detecting Catalyst in iOS Apps

At WWDC 2019 Apple announced that it’ll now be possible to port iOS apps to the Mac via a technology called Catalyst and ever since I’ve had a goal to bring an existing app of mine to the Mac App Store just to see what the process would look like.

I’ve been working on making my Color and Gradient maker, analyzer and editor app called Neon work on the Mac and even though I use storyboards, I don’t use segues and so it is important to know when the View Controller needs to be presented by pushing it onto the Navigation Stack, presented modally or needs to be presented in a new window and to do this I need a simple yet elegant solution to detect the device my app is being run on.

To accomplish this I built an extension for UIDevice. Please note that I’ve only accounted for iPhones, iPads, and Macs in this article.

Let’s get started by making an enum that will hold the different cases we’re dealing with

enum DeviceType {
    case phone
    case pad
    case mac
}

We’ll now make a if condition to check if the OS is Mac Catalyst and if not we’ll switch through the cases of UIDevice.current.userInterfaceIdiom to find out which iOS device our app is being run on.

extension UIDevice {
var deviceType: DeviceType? {
        #if targetEnvironment(macCatalyst)
            return .mac
        #else
        switch UIDevice.current.userInterfaceIdiom {
        case .phone:
            return .phone
        case .pad:
            return .pad
        default:
            return nil
        }
        #endif
    }
}

In the code above we are making a computed variable called deviceType that is of DeviceType (the enum we just made) and this will return the appropriate case of the device the app is currently being run on.

The main work is done and all that’s left is to execute and see how we can use it throughout our UIKit/SwiftUI Projects. For this example we’ll print out the return case in viewDidLoad() In your ViewController’s viewDidLoad() type this:

guard let type = UIDevice.current.deviceType else { return }
print(type)

Since Device Type is an optional (because it might return nil from the default condition of the switch case) we’ll unwrap it using a guard let statement and returning from the function early incase the value contains null. Once we know for sure that /type/ will have some value we print it out into the console. The console will contain the case related to the device we’re executing the application on.

If you liked this article you can

If you have any questions feel free to reach out to me on Twitter @SwapnanilDhol