SwiftUI vs. Jetpack Compose

Declarative UI Frameworks are on the rise. After third-party frameworks such as React Native, Litho and Component Kit, Apple and Google finally published their own solutions called Swift UI and Android’s Jetpack Compose.

Today, we will take a look at both and see where the main differences are, why those frameworks exist and how they change the way we develop apps.

Why a new UI Framework?

When talking about declarative UI, most people name frameworks like React or Flutter. Yet, those were not the first that described UI in a declarative manner. Even HTML and Android XML describe UI declaratively, meaning that they describe “what it should be like” instead of “how to create it”.

Declarative
Imperative

As you can see, modern declarative UI code feels more intuitive and makes it easier to express complex user interfaces with less code, making the life of us developers easier.

With imperative UI, the developer has to take care of updating every single View according to the data changes. On the other side, declarative UI defines how a View looks in a certain state. The mutated state will be reflected automatically in the UI.

Besides that, SwiftUI and Compose also take some learnings from the last few years of iOS and Android Development into account. SwiftUI, for example, makes it really easy to create a modern iOS app that conforms to the Human Design Guidelines by default and provides decent support for accessibility!

How does it look like?

Let’s jump right into some code and take a look at a simple example. We’ll display two buttons and a label. The label displays a count and the buttons are used to decrement or increment that count.

Both frameworks express this simple piece of UI in a similar way:

Android’s Jetpack Compose

SwiftUI

Just by looking at the structure of the code you can see – those two snippets look quite similar. Yet, there are a few small but important differences. Let’s break them down:

1. Structure

The first big difference is that Compose defines a piece of UI as a function and SwiftUI uses a struct.
The mental model for a UI component is more bare bones in Compose. It’s basically just the render function and nothing else. All of these, so called, render functions still need the @Composable annotation. Why is that?
Compose is responsible for building and maintaining tree-like data structures that represent the UI tree. These annotations generate code that helps Compose manage this tree. This includes that only the necessary functions are called whenever something changes.

The Swift UI toolchain does not generate code. In this case, we implement the View protocol by providing a computed View-property called body. This property returns the View tree that can be composed of multiple sub-Views.

2. State

Most of the times a View is bound to a state object. The View can modify this object and use the information to render the View. Whenever this state changes the View should be updated accordingly.

In our example, the state is called count . This is an instance of State that wraps the original type Int. In Compose this is created using val count = +state { 0 } . SwiftUI uses @State var count = 0  which is the syntax for a new feature in Swift called property wrappers. Both frameworks ensure that every consumer of these state objects will be updated whenever the state itself changes!

3. Defining the UI

SwiftUI and Compose provide Views that give you the ability to align your Views vertically, horizontally or on top of each other. The only big difference here is the naming. If you already wrote some Flutter code this concept might look familiar to you.

Compose SwiftUI
Row HStack
Column VStack
Stack ZStack

Styling, on the other hand, looks a little different. Let’s say we want to tint our buttons in a different color. In Compose this is done by passing the color into the function.


Swift UI uses View modifiers that wrap or adjust the given View and take care of changing the visuals.

Tooling

When designing UIs we like to iterate fast. We don’t want to rebuild our entire app just to see our button in another color. That’s why the new version of Xcode ships with a live preview that not only renders your UI but also lets you interact with it. The inspector was improved as well. You can now click on a View and it will display all the properties that can be tweaked. Once you adjust the property, the code in the editor reflects the change immediately.


The current version of Jetpack Compose does not ship with a live preview but this will change in the future since the website promises tools like Apply Changes and live preview.

Under the hood

Since Compose is fully open-source we took a look at how things are handled internally.
We also talked to developers from the Jetpack Compose Team who gave us a few more insights.
A really interesting design decision is that Compose is rendering most of its Views directly onto the canvas. The previous examples we showed didn’t make use of any Android Views internally. However, it is designed to work with Android Views as well. This interoperability is really important since complex Views such as WebView won’t be replaced anytime soon. Thanks to the Compose compiler the following code snippet works as well.

SwiftUI on the other side is different and less transparent. It can be a wrapper for NSView or UIView components. It can also be drawn by lower-level technologies. It’s important to understand that it does not have to be that way. SwiftUI is an abstraction layer that does the layouting but the underlying rendering can be different based on the platform it’s running on.

Developers should split their UI into smaller components that can be reused based on the target platform. SwiftUI is not designed to solve the “write once, run anywhere” problem. More like “learn once, write everywhere”.

Future

Since SwiftUI is already in beta we know a lot more about the direction Apple is taking with this UI framework. SwiftUI will most probably be the standard for UI development in the Apple ecosystem. It already provides tools and APIs to ship your app to all different Apple platforms including watchOS or macOS. However, SwiftUI is only supported since macOS Catalina and iOS 13. This means that we won’t see many apps migrating to SwiftUI soon. SwiftUI also makes it easier for Apple to add support for other platforms because of the new abstraction layer! Maybe we will have the option to create websites or progressive web apps with the support of Swift WebAssembly. Third-party developers were already able to build SwiftWebUI in a short amount of time.

Compose is in pre-alpha now and still in heavy development. It will probably be more than half a year until we can expect a stable version. Google hasn’t revealed any future plans for Compose but there are a few directions where this can go:

1. “Replacing” Android’s native Views.

Since Compose is taking care of rendering Views it is mostly decoupled from the operating system’s View drawing. That also means that you don’t have to wait for your users to adapt to newer Android versions in order to use newer APIs or UI components. You can just update Jetpack Compose and ship your app with new features!
This is huge if you keep device fragmentation in mind.

2. Moving to other platforms:

If you look at the Jetpack Compose source code you can see that it provides an abstraction for a canvas which could be implemented by any other target platforms such as iOS, Desktop or the Web.
Of course, there is much more than just the canvas but with Kotlin’s Multiplatform capabilities, the first steps are made!

Conclusion

We took a look at similar yet different frameworks that solve the same problem. Making UI development great again!

Compose took a few core principles from other frameworks such as Flutter and went for a solution that is more decoupled from the rest of the existing system. A few APIs we saw will probably change in the Future but the early preview already showed how Android UI development could look like in the future.

SwiftUI on the other side is investing heavily in growing other platforms in the Apple ecosystem such as watchOS, or macOS by utilizing existing APIs and taking the best from both worlds to make UI development more pleasant.

You should definitely keep an eye on both frameworks!