SECRET OF CSS

Exploring Rendering in SwiftUI. Learn when SwiftUI re-render subviews | by Riccardo Cipolleschi | Sep, 2022


Learn when SwiftUI re-render subviews

0*rdZRffU4d9SuwKYF 300w
Photo by Viktor Forgacs on Unsplash
0*U2lbEO8M90l7uDT 300w
Photo by Sebastian Svenson on Unsplash

One of the amazing aspect of the Software engineering profession is that you never stop learning. You are exposed every day to different technologies: learning their basic concepts is one of the things that I personally like the most.

One of the most important skills to learn new technologies is the ability to recognize patterns and similarities. This allows you to reason about a new technology even if you don’t use it every day.

A week ago, a colleague of mine sent me this article on React rendering. I don’t use React every day, but I am familiar with its basic concepts and I couldn’t notice how similar SwiftUI it is. While reading the article, I was surprised to see that React re-renders when the state of a Component changes and not when its props do.

So, my curiosity tingled: what does SwiftUI do? When it re-renders its components? I created a small project to try and understand that and today I want to share my process and my findings.

The first step I took was to reproduce the same situation of the one presented in the article. I created a new SwiftUI project with the same initial components:

  • The BigCountNumber
  • The Counter

For simplicity’s sake, I put them both in a single file:

Then, I changed the RenderingApp.swift to load the Counter view instead of the ContentView, so I could test it.

Running the app in the simulator, I could see the counter increasing every time I tapped on the button.

The second step was to understand how to visualize when a component was redrawn. I discovered the static_printDebug() function of SwiftUI’s View protocol: a private method that can be used to debug a SwiftUI View when it is rendered.

Caution: remember to remove this function call before submitting to Apple. Otherwise, your app will be automatically rejected: you can’t use private system APIs in your app.

When introducing a function call into the body of our View, we also have to add back the return statement: SwiftUI can’t infer what do you want to return if the body of the property is longer than a single statement.

The new code looks like this:

Running the App now, Xcode printed some messages in the console . At app launch, Xcode prints:

1*9OZqB8BZKo beYtJo1TK5A

And, after tapping on the increment button a few time, it prints:

1*LRKLAcQQ7ADXf2EdiTjySA

React and SwiftUI are currently behaving in the same way. In this setup, changing the State is the same as changing the properties of the involved components.

Let’s add the Decoration component as suggested by the reference article.

To track when the Decoration is rendered, I added the code to _printChanges. Let’s compose it with the Counter component, as shown in the article:

Running the app, Xocde prints the following output.

1*XWdXXIU8t EFHtZLTaYkWg

We can observe that Decoration appears only once, while both Counter and BigCountNumber get updated every time we click on the button.

By default, SwiftUI behaves in a more conservative way than React: it avoids unnecessary rendering of components whose props do not change.

My best explanation comes to the type semantic of the components. In SwiftUI, we create Views that are struct: by default immutable types. This makes much easier to verify when something changes and when not.

If the props of a View change, we have to recreate it: what we use in the body of a View are the initializers of the various components that create the View. We are basically telling the runtime: “Look, I’m creating a new view. Can you draw it?”.

React, on the other hand, works with reference types: class or function components. It is much harder (and expensive) understand when something changes: components are not continuously recreated. React has to decide when to invoke the render function (or the function that defines the component itself) again. When a variable of a class changes — like one of its props — the memory address of the class does not.

React promises to deliver the most updated version of the UI. To achieve that, it has to render its components more often than SwiftUI: every time the state change.

In today’s article, we explored the rendering differences between React and SwiftUI. We learned how to use the _printChanges private function to debug our rendering process and we created an experimental project to test it out.

We learned that SwiftUI redraws its component when their properties change and not when the state change, as React does. This is possible mainly to the value semantic of structs.



News Credit

%d bloggers like this: