June 3, 2019·6 min read·engineeringswiftswiftuiinterfaces

SwiftUI makes interface updates depend on declared state

Apple introduces SwiftUI with a declarative interface model and Xcode previews. The design moves update coordination into the framework while keeping application state explicit.

A screen can display the wrong information even when every individual control works. The application changes its model, but one label or list misses the corresponding update. SwiftUI addresses that coordination problem by making the interface a declaration of what the current data should display. Apple introduced the framework on June 3 alongside new graphical editing and preview tools in Xcode 11.

The announcement places SwiftUI across Apple platforms and describes automatic support for layout, accessibility, localization, and appearance. The same-day Platforms State of the Union presentation explains the relationship between model changes and view updates. Existing models can announce changes through the new bindable-object protocol, while temporary interface state can use a state wrapper. The interface then updates in response to the declared data.

I find that relationship consistent with the parts of Swift I like. Explicit values make code easier to reason about locally. An interface description built around its inputs offers a similar advantage, provided the application remains clear about which data it owns and which data the framework observes.

An update is a dependency between data and presentation

Consider a screen showing a selected item and a short summary of that item. An imperative implementation can assign the selected item to one variable, set the title label, and then replace the summary text. The intended relationship among those operations exists in the programmer's understanding. Every path that changes the selection has to preserve it.

A declarative description moves that relationship into the definition of the screen. The title and summary derive from the selected item. Changing the selection no longer requires the caller to know every piece of presentation that depends on it. This is an architectural benefit because it reduces the amount of interface knowledge required at the place where state changes.

That arrangement does not establish that the selection is correct. A framework can faithfully display an incorrectly selected item. It can also faithfully display stale data that the application has not replaced. The guarantee being sought concerns consistency between declared inputs and their presentation. Network freshness and business rules remain properties of the application.

This distinction helps explain where complexity moves. An application still needs to decide when a request begins and how its response affects the model. It still needs to distinguish a successful empty result from a failed request if the interface presents them differently. The declarative description can make those states visible, but it does not choose the domain model on the application's behalf.

For example, a loading flag and a result value can be updated independently into an unintended combination. A presentation framework cannot infer whether that combination is legal. A model that represents the intended states explicitly gives the interface a better input. The design of the state remains consequential even when assigning every control is no longer the developer's job.

A useful model can also distinguish a saved selection from a temporary selection being edited. Without that distinction, cancelling an interaction becomes ambiguous because the application has already overwritten its durable choice. Declaring the interface in terms of state makes this ownership question easier to identify, but the application still has to answer it.

Composition changes the unit of interface work

The presentation demonstrates composing small views through containers and applying common modifiers. That makes a reusable view a useful place to describe a bounded relationship between data and appearance. The application can separate a summary view from the surrounding navigation without requiring the summary to know how its parent handles every event.

A component boundary becomes useful when its inputs explain its output. A title and a secondary value might be sufficient for a simple summary. Passing an entire mutable application model grants much broader access than the view needs. The choice affects how easily another developer can understand the component and supply representative data for it.

Composition also has a practical relationship to review. A change confined to a view description can show the structure and its presentation choices together. A reviewer has less need to reconstruct that structure from a series of setup calls scattered across lifecycle methods. This is an advantage of keeping the description coherent, rather than an automatic property of all code written with a new framework.

An excessively large declaration can still become difficult to understand. Extracting a component should give a meaningful name to a portion of the interface with a clear input contract. Dividing a declaration solely to reduce line count does not necessarily improve that contract. The useful boundary follows the information displayed or the interaction supported.

I am interested in this because small applications should not need extensive coordination code merely to keep a modest screen current. A concise view declaration can reduce that work. The remaining model and component boundaries deserve the same attention as they would in an imperative implementation.

Previews make representative inputs part of development

Xcode's new previews use project code to configure a view for design-time inspection. The demonstration shows several previews of the same component with different data and display settings. It also shows interactive previews and deployment to a connected device. The important design property is that the preview configuration lives with the project instead of existing only as a transient editor action.

That makes representative inputs useful artifacts. A component can be examined with an ordinary title and then with a much longer one. A view that handles no content can be compared with the same view containing several items. These comparisons concern layout and presentation before the developer has to navigate a complete application into each condition.

Preview data should describe valid states that the view can receive. A collection of attractive examples with uniformly short strings gives little information about constraints that real content may encounter. A useful preview set contains differences that can change the layout or interpretation. The objective is to expose the consequences of the input contract.

An interactive preview serves another purpose. A static image can show that a control fits, but it cannot show the sequence of state changes caused by using it. Exercising a preview can reveal whether a visual transition communicates the intended result. It still cannot establish that an unrelated service or persistence operation behaves correctly outside that configured example.

My concern about Swift build times makes the iteration workflow particularly interesting. The preview model gives the tools a smaller piece of interface to present while the developer works. That is a reason to examine the workflow, without assuming that every project gains the same compilation improvement or that a live preview replaces tests of the complete application.

Automatic behavior needs appropriate inputs

The announcement's accessibility and localization support has architectural implications beyond reducing setup code. A framework can supply standard behavior when an application uses controls and values whose purpose it understands. A custom interaction that communicates only through an unexplained visual effect gives the framework less information to work with.

The application therefore still has to express meaning. A useful label says what an action does. State changes should preserve the distinction between a pending operation and one that has completed. A declarative framework can coordinate the presentation of those meanings, but an incorrect or absent meaning remains an application defect.

Sharing interface code across platforms raises a related question about input assumptions. A common view can describe information that several devices display. Its surrounding interaction still needs to respect how the user selects or manipulates that information on each device. Reuse becomes easier when the common component does not assume every platform has the same input method or navigation structure.

The State of the Union explicitly describes incremental adoption alongside UIKit, AppKit, and WatchKit. That permits a bounded experiment inside an existing application. A new view can receive a defined set of inputs while the rest of the application keeps its current architecture. This is a useful way to evaluate whether its state model fits the new declaration style without requiring an immediate rewrite of every screen.

The boundary between that view and its existing host remains substantive engineering work. The host needs to supply current inputs and receive the effects of user actions without introducing a second, conflicting copy of the same state. Defining that ownership makes incremental adoption understandable, because there is a clear answer to which component decides the value being displayed.