The Redacted View Modifier in SwiftUI

Posted in SwiftUI

November 5th, 2021

⏱ Reading Time: 5 mins

It is an undeniable fact that the essence and the real identity of each app is its content. That, in combination to its design and provided user experience, makes every app unique and different. However, it’s sometimes necessary to replace part of, or the entire content with placeholders. And there are two main reasons to do that:

  • To hide sensitive or private data.
  • To indicate that some content is about to be displayed, but it is not ready or available to use yet.

Undoubtedly, there are various solutions that we could put in motion instead of placeholders; to display nothing at all, an activity indicator, or some other temporary content. However, SwiftUI has a special view modifier that can obscure any view by covering it with an overlay automatically. It’s really the most suitable solution to resort to in many cases, and it leads to a quite beautiful user experience; that is the redacted(reason:) view modifier.

Redacting specific views

The best way to demonstrate a concept is through an example. So, consider the following simple SwiftUI view implementation that presents a title along with the username and password of a hypothetical logged in user:

Fake credentials shown as plain text

The fake password shown above is sensitive data; a third-party person could easily sneak a peek to the user’s device and find out the what the password is. If we were to make this app for real, then it would be truly unacceptable to show the password as plain text.

It would be more appropriate to cover the password, and have a button allowing to show it on demand:

In SwiftUI it’s really easy to cover a view with the redacted(reason:) view modifier:

The reason argument indicates to SwiftUI why the redaction is necessary. It can be a single value as shown above, or a set of reasons. At the time of writing there are two redaction reasons; placeholder and privacy, with the latter being available in iOS 15 and above.

That small addition results to this, which is a proper way to deal with sensitive data:

Fake credentials with the password covered with redacted placeholder

Redacting the entire view contents

What I just showed in the previous example is how to use the redacted(reason:) view modifier in order to hide a specific view. It’s possible, however, to cover all views in a view hierarchy. Suppose that we have the next implementation that shows a title and a hypothetical list of users:

In real scenarios, if user list is fetched from a remote server, or loaded from a local database, it might take some amount of time until all data is available to display. In that case, we want the app’s users to know that some content is about to come, but it’s not ready yet; the redacted(reason:) view modifier is a nice approach in order to keep them engaged, but in this case it’s necessary to cover the entire area where the actual content will be shown.

Instead of applying the redacted(reason:) to each inner view specifically, we may apply it either to the outermost container view, or to the view itself on the call site:

Any of the above will cover all nested views in the VStack above with an overlay:

Full view hierarchy redacted containing a title and a fake list of users

Note though that when actual data becomes available we should update the displayed state. For example, we may use the .placeholder value at first and while loading data, but replace it with an empty set in order to show real data at the proper moment like so:

isLoading indicates whether the app is still loading its data or not.

Avoiding redacting all views

The problem in the above example is that the Text view working as the view’s title is redacted as well. That’s not so user-friendly, and there is no real reason to keep it hidden even when no data is still available to show.

SwiftUI makes it easy for us to fix such situations by providing us with another view modifier, called unredacted(). Simply enough, we just apply it to the view we want to maintain intact and unaffected by the redacted(reason:) view modifier:

List of fake users redacted with the title unredacted

Watch out for actionable views

Extending the previous simple example a bit, suppose that we have a button at the bottom of the view that we can tap in order to load more data:

View with redacted button along with redacted fake list of users

As you realize, by applying the redacted(reason:) view modifier to the container view, the button will become covered as well. However, there is a catch here; the button remains tappable even when it’s redacted.

It’s our duty to allow or not the execution of the button’s assigned action when the redacted modifier hides the view’s content. That’s important to keep in mind and act appropriately in order to avoid unwanted behavior from the app when using the modifier’s effects.

The solution to this particular case is simple:

Determining the redaction reasons

While redacting views in order to provide a better user experience in our apps, it might be necessary sometimes to know the current value of the redaction reason. When having that information, it’s easy to show or hide parts of the view conditionally, or to perform any other actions.

We can fetch the current redaction reason in a SwiftUI view by accessing the following environment variable:

Using the example from the previous part, we can now be based on the redactionReasons value and show the button to fetch more data only when the redaction reason is not placeholder:

As a word of notice, and in order for this to work, make sure that you redact views in the view hierarchy by applying the redacted(reason:) modifier in the view’s call site. Don’t do so in the outermost container view:

Conclusion

The redacted(reason:) view modifier is a great way to show visual placeholders while waiting for actual data, or to cover private and sensitive information. Use it to hide one or more views in the view hierarchy as needed. But also use unredacted() in order to keep certain views normally visible always. It definitely is a pretty handy tool that SwiftUI provides us with, as it makes it easier to give users a beautiful experience.

Thank you for reading, take care! ????

Stay Up To Date

Subscribe to my newsletter and get notifiied instantly when I post something new on SerialCoder.dev.

    We respect your privacy. Unsubscribe at any time.